欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
NOIP復賽復習(十七)剪枝與坐標離散化

定期推送信息學(xué)新聞,競賽自主招生,信息學(xué)專(zhuān)業(yè)知識,信息學(xué)疑難解答,融科教育信息學(xué)培訓等諸多優(yōu)質(zhì)內容的微信平臺,歡迎分享文章給你的朋友或者朋友圈!


一、剪枝

在搜索算法中優(yōu)化中,剪枝,就是通過(guò)某種判斷,避免一些不必要的遍歷過(guò)程,形象的說(shuō),就是剪去了搜索樹(shù)中的某些枝條,故稱(chēng)剪枝。應用剪枝優(yōu)化的核心問(wèn)題是設計剪枝判斷方法,即確定哪些枝條應當舍棄,哪些枝條應當保留的方法。 

剪枝算法按照其判斷思路可大致分成兩類(lèi):可行性剪枝及最優(yōu)性剪枝。

 

POJ2676

給你一個(gè)9*9的九宮格,有部分已經(jīng)填上了數字,要求將九宮格用1-9填滿(mǎn),每行中的數字各不相同,每列中的數字各不相同,從從第一行開(kāi)始每3*3組成一個(gè)小九宮格,小九宮格中的數字也各不相同。 

解題思路,從左上角開(kāi)始試著(zhù)填數,這個(gè)數應該是該行、該列和方塊中都未出現的數字(因此,需要判斷一個(gè)格子是否能填某個(gè)數),這個(gè)方法叫做剪枝,深度優(yōu)先搜索直到填滿(mǎn)所有的數。

 

#include

#include

using name space std;

int a[10][10];

char s[10][10];

//下標都是從08

//判斷(x,y)處能否放置k

bool flag;

bool ok(int k,int x,int y)

{

    for(int i=0;i<>

        if(a[i][y]==k) return false;

    }

    for(int j=0;j<>

        if(a[x][j]==k) return false;

    }

    int u=x-x%3,v=y-y%3;

    for(int i=u;i<>

        for(int j=v;j<>

            if(a[i][j]==k) return false;

        }

    }

    return true;

}

//從當前點(diǎn)(x,y)開(kāi)始深度優(yōu)先搜索

void dfs(int x,int y)

{

    //flag是成功的標志,而放置數字是按行從上到下開(kāi)始,因此x==9也是成功的標志

    if(flag||x==9){

        flag=true;

        return;

    }

    //(x,y)處已放置數字,放置下一個(gè)格子

    while(a[x][y]){

        if(y==8){

            x++;

            y=0;

        }

        else y++;

        if(x==9){

            flag=true;

            return;

        }

    }

    //枚舉九個(gè)數字

    for(int k=1;k<>

        if(ok(k,x,y)){

           a[x][y]=k;

           if(y==8) dfs(x+1,0);

           else dfs(x,y+1);

           if(flag) return;

           a[x][y]=0;

        }

    }

}

int main()

{

    int t;

    scanf('%d',&t);

    while(t--){

        for(int i=0;i<>

            scanf('%s',s[i]);

            for(int j=0;j<>

                a[i][j]=s[i][j]-'0';

            }

        }

        flag=false;

        dfs(0,0);

        for(int i=0;i<>

            for(int j=0;j<>

                printf('%d',a[i][j]);

            }

            printf('\n');

        }

    }

    return 0;

}

 

POJ1084

題意:n*n的矩形陣(n<>,由2*n*(n+1)根火柴構成,那么其中會(huì )有很多諸如邊長(cháng)為1,為2...n的正方形,現在可以拿走一些火柴,那么就會(huì )有一些正方形被破壞掉。問(wèn),在已經(jīng)拿走一些火柴的情況下,還需要拿走至少多少根就可以把所有的正方形破壞掉。 

題解:可以用dancing links做,讓火柴做為行,讓所有的正方形作為列,且如果i火柴能讓j正方形破壞掉,就讓第i行第j列為1,然后做一次可重復的覆蓋,取最小值便可以得到答案。另外,涉及兩個(gè)優(yōu)化,

1、最優(yōu)化剪枝,即最好情況下也不會(huì )比當前最優(yōu)值更優(yōu)的剪枝。

2、不必一開(kāi)始就將所有的火柴棍與正方形的對應關(guān)系加入到DLX中,應該在讀完所有數據之后,判斷哪些正方形已經(jīng)被刪除了(即該列無(wú)效),只加入有效的結點(diǎn)。

 

#include

#include

#include

using name space std;

const int inf=1<>

const int NUM=100*60;

int cnt,L[NUM],R[NUM],S[NUM],D[NUM],U[NUM],C[NUM],O[NUM],H[NUM],X[NUM];

/*

    NUM:最大結點(diǎn)數

    U,D,L,R:上下左右結點(diǎn)

    C:列的頭指針位置

    O:儲存答案

    X:與O配合代表第幾行(X[O[i]]]

    通過(guò)linkr,c)加點(diǎn),dfs0)運算

*/

void remove(int c)

{

    for(int i=D[c];i!=c;i=D[i])

    {

        L[R[i]]=L[i];

        R[L[i]]=R[i];

    }

}

void resume(int c)

{

    for(int i=D[c];i!=c;i=D[i])

    {

        L[R[i]]=i;

        R[L[i]]=i;

    }

}

int geth()

{

    bool has[80];

    memset(has, false, sizeof(has));

    int res=0;

    for(int i=R[0]; i!=0; i=R[i])

        if(!has[i])

        {

            res++;

            for(int j=D[i]; j!=i; j=D[j])

                for(int k=R[j]; k!=j; k=R[k])

                    has[C[k]]=true;

        }

    return res;

}

int ans;

void dfs(int k)

{

    if(!R[0])

    {

        ans=min(k,ans);

        return;

    }

    else if(k+geth()>=ans)

        return;

    int c=R[0];

    for(int t=R[0],ms=inf; t!=0; t=R[t])

        if(S[t]<>

            ms=S[t],c=t;

    for(int i=D[c];i!=c;i=D[i])

    {

        remove(i);

        for(int j=R[i]; j!=i; j=R[j])

        {

            remove(j);

            S[C[j]]--;

        }

        dfs(k+1);

        for(int j=L[i]; j!=i; j=L[j])

        {

            resume(j);

            S[C[j]]++;

        }

        resume(i);

    }

}

void build(int r,int c)

{

    for(int i=0;i<>

    {

        U[i]=D[i]=i;

        L[i+1]=i;

        R[i]=i+1;

        C[i]=i;

        S[i]=0;

    }

    R[cnt=c]=0;

    while(r)

        H[r--]=-1;

}

void link(int r,int c)

{

    ++S[C[++cnt]=c];

    X[cnt]=r;

    D[cnt]=D[c];

    U[D[c]]=cnt;

    U[cnt]=c;

    D[c]=cnt;

    if(H[r]<>

        H[r]=L[cnt]=R[cnt]=cnt;

    else

    {

        R[cnt]=R[H[r]];

        L[R[H[r]]]=cnt;

        L[cnt]=H[r];

        R[H[r]]=cnt;

    }

}

bool mark[80][80];

void init(int n)

{

    memset(mark,false,sizeof(mark));

    int i,j,k,si,num=0,c=1;

    for(si=1;si<>

    {

        for(i=1;i<>

        {

            for(j=1;j<>

            {

                for(k=0;k<>

                {

                   mark[(i-1)*(2*n+1)+j+k][c]=true;

                   mark[(i-1+si)*(2*n+1)+j+k][c]=true;

                   mark[i*n+(i-1)*(n+1)+j+k*(2*n+1)][c]=true;

                    mark[i*n+(i-1)*(n+1)+j+k*(2*n+1)+si][c]=true;

                }

                c++;

            }

        }

    }

}

int main()

{

    int T,n;

    for(scanf('%d',&T);T;T--)

    {

        scanf('%d',&n);

        int num,row=2*n*(n+1),col=0;

        for(int i=1;i<>

            col+=i*i;

        build(row,col);

        init(n);

        scanf('%d',&num);

        bool vis[80];

        memset(vis,false,sizeof(vis));

        for(int i=0;i<>

        {

            int r;


            scanf('%d',&r);

            for(int j=1;j<>

            {

                if(mark[r][j])

                {

                    if(!vis[j])

                    {

                        vis[j]=true;

                        R[L[j]]=R[j];

                        L[R[j]]=L[j];

                        R[j]=L[j]=0;

                    }

                }

            }

        }

        for(int i=1;i<>

            for(int j=1;j<>

                if(mark[i][j]&&!vis[j])

                    link(i,j);

        ans=100000;

        dfs(0);

        printf('%d\n',ans);

    }

    return 0;

}

 

二、坐標離散化 

區域的個(gè)數:w*h的格子上畫(huà)了n條或垂直或水平的寬度為1的直線(xiàn),求出這些線(xiàn)將格子劃分成了多少個(gè)區域。 

已知:

1≤w,h≤1000000

1≤n≤500 

sample input

w= 10,h = 10,n = 5

x1= {1 , 1 , 4 , 9 , 10}

y1= {4 , 8 , 1 , 1 , 6}

x2= {6 , 10 , 4 , 9 , 10}

y2= {4 , 8 , 10 , 5 , 10}

(對應上圖,橫向為x,縱向為y) 

利用BFSdfs可以求出被分割的區域,但是w,h太大,不能創(chuàng )建w*h的數組,所以需要用到坐標離散化” 這一技巧。如下圖:

 

將前后左右沒(méi)有變化的行列消除后并不會(huì )影響區域的個(gè)數。數組里重要存儲有直線(xiàn)的行列以及其前后的行列就足夠了。這樣的話(huà)最多6n*6n就足夠了,因此可以創(chuàng )建出數組并利用搜索求出區域的個(gè)數。

#include

#include

#include

#include

#include

#include

#include

using name space std; 

const int maxn = 500;

int W,H,N;

int X1[maxn],X2[maxn],Y1[maxn],Y2[maxn];

bool fld[maxn*6][maxn*6];

int dx[4]={0,0,-1,1};

int dy[4]={1,-1,0,0}; 

//x1x2進(jìn)行坐標離散化,并返回離散后的寬度。(對于y1,y2同理)

//x1,x2更新為離散后的x1,x2.y不變在x方向上縮小。(處理y1,y2時(shí)同理)

int compress(int *x1,int *x2,int w)

{

    vector xs;

    for(int i = 0;i <>//確定離散后x軸上哪些值還存在

    {

        for(int d = -1;d <= 1;="">

        {

            int tx1 = x1[i] + d, tx2 = x2[i] +d;

            if(1 <= tx1="" &&="" tx1=""><=w)>

            if(1 <= tx2="" &&="" tx2=""><=w)>

        }

    }

    sort(xs.begin(),xs.end());

    xs.erase(unique(xs.begin(),xs.end()),xs.end());//去重

    for(int i = 0; i < n;="">//轉化為新的x1,x2;

    {

        x1[i] =find(xs.begin(),xs.end(),x1[i])-xs.begin();

        x2[i] =find(xs.begin(),xs.end(),x2[i])-xs.begin();

    }

    return xs.size();

} 

void solve()

{

    //離散化

    W = compress(X1,X2,W);

    H = compress(Y1,Y2,H);

    //填充新的網(wǎng)格

    memset(fld,0,sizeof(fld));

    for(int i=0;i<>

    {

        for(int y=Y1[i];y<>

        {

            for(int x=X1[i];x<>

            {

                fld[y][x]=true;

            }

        }

    }

    //利用BFS計算區域數

    int ans=0;

    for(int y=0;y<>

    {

        for(int x=0;x<>

        {

            if(fld[y][x]) continue;

            ans++;

            queue<> >que;

            que.push(make_pair(x,y));

            while(!que.empty())

            {

                int sx=que.front().first,sy=que.front().second;

                que.pop();

                for(int i=0;i<>

                {

                    int tx=sx + dx[i],ty=sy +dy[i];

                    if(tx<0 ||="" tx="">=W ||ty<0 ||="" ty="">=H || fld[ty][tx]) continue;

                    que.push(make_pair(tx,ty));

                    fld[ty][tx]=true;

                }

            }

        }

    }

    printf('%d\n',ans);

} 

intmain()

{

   while(scanf('%d%d%d',&W,&H,&N)==3)

    {

        for(int i=0;i<>

            scanf('%d',&X1[i]);

        for(int i=0;i<>

            scanf('%d',&X2[i]);

        for(int i=0;i<>

            scanf('%d',&Y1[i]);

        for(int i=0;i<>

            scanf('%d',&Y2[i]);

            solve();

    }

    return 0;

} 

/*

輸入:

1010 5

11 4 9 10

610 4 9 10

48 1 1 6

48 10 5 10

輸出:

6

*/


本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
天梯 - 紅色警報(判斷去掉一個(gè)節點(diǎn)后的連通分支數是否改變)
NOIP 2016 Day 1 題解 | Sengxian's Blog
飛花如夢(mèng),陽(yáng)光燦爛的日子
剪枝算法(算法優(yōu)化)
(轉)樹(shù)狀數組
樹(shù)鏈剖分詳解及模板
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久