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.
3 3 4 1 2 1 3 2 1 2 2 3 3 4 1 2 1 3 2 1 3 2
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; }