toj 3345. Chinese Chess 關鍵匹配

來源:互聯網
上載者:User

3345.   Chinese Chess

Time Limit: 20.0 Seconds   Memory Limit: 65536K
Total Runs: 426   Accepted Runs: 47



Winnie is very interested in chinese chess. Now, let's consider a game which is similar to it. There is a  N *  M chess board, we hope we can put rooks as more as possible. But just a certain number of
postions can be put rooks on. One rook can attack another if they are in the same row or column. Now you may think this is a very simple problem for you. But as very whuacmers know, winnie is evil enough to cheat you. Let's consider some positions called critical
postions. If we don't put rook on the critical position, the maximum number of rook we can put on this chess board will reduce. How many critical positions on the chess board?

Input

Input will contain multiple test cases. The first line contains three numbers NMK(NM ≤ 10000, K ≤ 100000) which indicate height, width and number of positions which can be put rook on. Then next K lines
follow, each contains two integer X ans Y which indicate we can put rook on the Xth row, Yth column.

Output

Output as follow:

Board T have C important blanks for L chessmen.

C indicate the number of critical positions ans L indicate the maximum rooks can be put.

Sample Input

3 3 41 21 32 12 23 3 41 21 32 13 2 
Sample Output

Board 1 have 0 important blanks for 2 chessmen.Board 2 have 3 important blanks for 3 chessmen. 

Hint: huge input, use scanf please.


題意:棋盤上有很多點,問最少設定幾個棋子可以把這些點都吃掉,還問哪些棋子放置的位置是固定的,不然有些點就不能被吃掉

關鍵匹配:

先找到最大匹配。

然後對每個匹配邊的兩個端點u,v查看是否對應唯一的匹配邊,

不最佳化會逾時的。看了別人的代碼才發現可以這樣最佳化。太神奇了

其中有兩處最佳化

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int maxn = 10009;int cover[maxn],pre[maxn],son[maxn],flag[maxn];vector<int>head1[maxn],head2[maxn];int nodeu,nodev;int findx(int u){//尋找左側點的增廣路    for(int i = 0;i < head1[u].size();i++){        int v = head1[u][i];        if(cover[v] == 1)continue;        if(nodeu == u && nodev == v)continue;        cover[v] = 1;        if(pre[v] == -1 || findx(pre[v]) == 1){            pre[v] = u; son[u] = v;            return 1;        }    }    return 0;}int N,M;int begin(){//二分匹配    int res = 0;    memset(pre,-1,sizeof(pre));    memset(son,-1,sizeof(son));    for(int i = 1; i <= N; i++){//最佳化,枚舉每條邊,查看是否可以找到匹配邊        if(son[i] != -1) continue;        for(int j = 0;j < head1[i].size() && son[i] == -1;j++){            int v = head1[i][j];            if(pre[v] == -1){                pre[v] = i; son[i] = v;res++;            }        }    }    for(int i = 1;i <= N; i++){//尋找增廣路,增加匹配邊        if(son[i] != -1) continue;        memset(cover,0,sizeof(cover));        if(findx(i) == 1) res++;    }    return res;}int findy(int v){//尋找右側點的增廣路    for(int i = 0;i < head2[v].size();i++){        int u = head2[v][i];        if(nodeu == u && nodev == v) continue;        if(cover[u] == 1) continue;        cover[u] = 1;        if(son[u] == -1 || findy(son[u]) == 1){            son[u] = v; pre[v] = u;            return 1;        }    }    return 0;}int work(){    int ans = 0; int flag2 = 0;    for(int i = 1;i <= N; i++) flag[i] = son[i];    for(int i = 1;i <= N; i++){        if(flag[i] == -1) continue;        nodeu = i, nodev = son[i];        son[nodeu] = -1; pre[nodev] = -1;        flag2 = 0;//查看一條邊的兩個端點是否都沒有增廣路        //沒有說明這條是關鍵匹配        memset(cover,0,sizeof(cover));        if(findx(nodeu) == 1) flag2 = 1;        else{            memset(cover,0,sizeof(cover));            if(findy(nodev) == 1) flag2 = 1;        }        if(flag2 == 0){son[nodeu] = nodev ; pre[nodev] = nodeu; ans++;}        else for(int j = i; j <= N; j++)//核心最佳化,可以沒有else直接最佳化                if(son[j] != flag[j]) flag[j] = -1;        //如果在尋找增廣路時,匹配邊上的點發生變化,說明表示關鍵匹配,        //下次無需再進行判斷了    }    return ans;}int main(){    int u,v,k,t=1;    while(scanf("%d%d%d",&N,&M,&k) != EOF){        for(int i = 1;i <= N; i++) head1[i].clear();        for(int i = 1;i <= M; i++) head2[i].clear();        for(int i = 0;i < k ;i++){            scanf("%d%d",&u,&v);            head1[u].push_back(v);            head2[v].push_back(u);        }        nodeu  = -1,nodev = -1;        int res = begin();        int ans = work();        printf("Board %d have %d important blanks for %d chessmen.\n",t++,ans,res);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.