1.hdu1045
题意:给出一张图,图中'X'表示wall,'.'表示空地,可以放置blockhouse
同一条直线上只能有一个blockhouse,除非有wall隔开,问在给出的图中
最多能放置多少个blockhouse
每个边界与X都可以看成是点,.是边连的是离它最近的上面左面的两个边或者X
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa = 40; char mp[maxa][maxa]; int num[maxa][maxa]; int main(){ int n; while(scanf("%d", &n), n){ for(int i = 0; i <= n; i++){ for(int k = 0; k <= n; k++){ mp[i][k] = 'X'; } } for(int i = 1; i <= n; i++){ scanf("%s", mp[i]+1); } /*for(int i = 0; i <= n; i++){ printf("%s ", mp[i]); }*/ int nn = 0; for(int i = 0;i <= n; i++){ for(int k = 0; k <= n; k++){ if(mp[i][k] == 'X') num[i][k] = nn++; } } for(int i = 0; i < nn; i++){ g[i].clear(); } for(int i = 1 ;i <= n; i++){ for(int k = 1; k <= n; k++){ int x, y; if(mp[i][k] == '.'){ for(int j = k-1; j >= 0; j--){ if(mp[i][j] == 'X'){ x = num[i][j]; break; } } for(int j = i-1; j >= 0; j--){ if(mp[j][k] == 'X'){ y = num[j][k]; break; } } //printf("%d %d ", x, y); g[x].push_back(y); } } } Nx = nn; printf("%d ", MaxMatch()); } }
2.hdu3605
题意:有 n 个人选择 m 个星球居住,选择情况和星球居住上限有限制,问是否能全部满足要求。
状态压缩+二分图
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define MAXM 555555 #define MAXN 2222 struct Edge{ int v,cap,next; }edge[MAXM]; int pre[MAXN]; int cur[MAXN]; int head[MAXN]; int level[MAXN]; int gap[MAXN]; int n,m; int NV,NE; void init(){ NE = 0; memset(head, -1, sizeof(head)); } int SAP(int vs,int vt){ memset(pre,-1,sizeof(pre)); memset(level,0,sizeof(level)); memset(gap,0,sizeof(gap)); for(int i=0;i<=NV;i++)cur[i]=head[i]; int u=pre[vs]=vs,maxflow=0,aug=-1; gap[0]=NV; while(level[vs]<NV){ loop: for(int &i=cur[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].cap&&level[u]==level[v]+1){ aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap)); pre[v]=u; u=v; if(v==vt){ maxflow+=aug; for(u=pre[u];v!=vs;v=u,u=pre[u]){ edge[cur[u]].cap-=aug; edge[cur[u]^1].cap+=aug; } aug=-1; } goto loop; } } int minlevel=NV; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].cap&&minlevel>level[v]){ cur[u]=i; minlevel=level[v]; } } gap[level[u]]--; if(gap[level[u]]==0)break; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } return maxflow; } void addedge(int u,int v,int cap,int cc=0){ //printf("*%d %d %d ", u, v, cap); edge[NE].cap=cap;edge[NE].v=v; edge[NE].next=head[u];head[u]=NE++; edge[NE].cap=cc;edge[NE].v=u; edge[NE].next=head[v];head[v]=NE++; } int num[(1<<11) + 100]; int main(){ int n, m; while(scanf("%d%d", &n, &m)!=EOF){ //将所有的点压缩到1~(1<<m) - 1 num 表示这样的人有多少 init(); memset(num, 0, sizeof(num)); for(int i =0;i < n; i++){ int id = 0; for(int k = 0; k < m; k++){ int x; scanf("%d", &x); if(x){ id += 1<<k; } } num[id] ++; } for(int i = 0;i < m; i++){ int x; scanf("%d", &x); num[(1<<m) + i] = x; //星球的点变成(1<<m) + i num表示每个星球能够承载的人数 } int src = (1<<m) +m + 1; int sink = (1<<m) + m +2; NV = sink+1; for(int i = 0;i < (1<<m); i++){ addedge(src, i, num[i]); //从起点到每种人建立一条人数的边 for(int k = 0; k < m;k ++){ if((1<<k) & i){ addedge(i,(1<<m) + k, num[i]); //每种人到对应的每个星球都建立一条人数的边 } } } for(int i =0 ;i < m; i++){ addedge(i+(1<<m), sink, num[i+(1<<m)]); //星球到终点建立一条星球能承载最大人数的边 } //printf("%d ", SAP(src, sink)); if(SAP(src, sink) == n) printf("YES "); else printf("NO "); } }
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa = 400; char mp[maxa][maxa]; int num[maxa][maxa]; int main(){ int n, m; int t; scanf("%d", &t); while(t--){ scanf("%d%d", &n, &m); for(int i = 0; i <= n; i++){ for(int k = 0; k <= m; k++){ mp[i][k] = '#'; } } for(int i = 1; i <= n; i++){ scanf("%s", mp[i]+1); } /*for(int i = 0; i <= n; i++){ printf("%s ", mp[i]); }*/ int nn = 0; for(int i = 0;i <= n; i++){ for(int k = 0; k <= m; k++){ if(mp[i][k] == '#') num[i][k] = nn++; } } for(int i = 0; i < nn; i++){ g[i].clear(); } for(int i = 1 ;i <= n; i++){ for(int k = 1; k <= m; k++){ int x, y; if(mp[i][k] == '*'){ for(int j = k-1; j >= 0; j--){ if(mp[i][j] == '#'){ x = num[i][j]; break; } } for(int j = i-1; j >= 0; j--){ if(mp[j][k] == '#'){ y = num[j][k]; break; } } //printf("%d %d ", x, y); g[x].push_back(y); } } } Nx = nn; printf("%d ", MaxMatch()); } }
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=111; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; int g[MAXN][MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int v =0 ; v < Ny; v++){ if(g[u][v] && dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int v = 0; v < Ny; v++){ if(g[u][v] && !vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa = 105 * 111; int x[maxa], y[maxa]; int main(){ int n, m, q; int cas = 1; while(scanf("%d%d%d", &n, &m, &q)!=EOF){ memset(g, 0, sizeof(g)); for(int i =0 ;i < q; i++){ scanf("%d%d", &x[i], &y[i]); g[x[i]][y[i]] = 1; } Nx = n+1; Ny = m+1; int sum = MaxMatch(); int ans = 0; for(int i =0 ;i < q; i++){ g[x[i]][y[i]] = 0; if(MaxMatch() < sum) ans ++; g[x[i]][y[i]] = 1; } printf("Board %d have %d important blanks for %d chessmen. ", cas++, ans, sum); } }
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } int main(){ int q, m, n; while(scanf("%d", &q)!=EOF){ if(q == 0) return 0; scanf("%d%d", &m, &n); for(int i = 1; i <= m; i++){ g[i].clear(); } while(q--){ int x, y; scanf("%d%d", &x, &y); g[x].push_back(y); } Nx = m+1; printf("%d ", MaxMatch()); } }
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa =111; char mp[maxa][maxa]; int num[maxa][maxa]; int move[4][2] = {0, 1, 0, -1, 1, 0, -1, 0}; int main(){ int t, n, m; scanf("%d", &t); while(t--){ scanf("%d%d", &n, &m); for(int i = 0;i < n; i++){ scanf("%s", mp[i]); } int sum = 0; for(int i = 0; i < n; i++){ for(int k = 0;k < m; k++){ if(mp[i][k] == '*'){ sum ++; } } } Nx = 0; for(int i =0 ;i < n; i++){ for(int k =0 ;k < m; k++){ num[i][k] = Nx ++; } } for(int i =0;i < Nx; i++){ g[i].clear(); } for(int i = 0;i < n; i++){ for(int k = 0; k < m; k++){ if((i+k) %2 == 1 && mp[i][k] == '*'){ for(int j = 0; j < 4;j++){ int x = i+ move[j][0], y = k + move[j][1]; if(0 <= x && x < n && 0 <= y && y < m && mp[x][y] == '*'){ g[num[i][k]].push_back(num[x][y]); } } } } } //printf("%d ", sum); printf("%d ", sum -MaxMatch()); } }
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa =111; char mp[maxa][maxa]; int num[maxa][maxa]; int MOVE[4][2] = {0, 1, 0, -1, 1, 0, -1, 0}; int main(){ int n, m, q; while(scanf("%d%d%d", &n, &m , &q)!=EOF){ int sum ; for(int i =0 ;i < n; i++){ for(int k =0 ;k < m;k ++){ mp[i][k] = '*'; } } while(q--){ int x, y; scanf("%d%d", &y, &x); x--, y--; mp[x][y] = '&'; } Nx = 0; for(int i =0 ;i < n; i++){ for(int k =0 ;k < m; k++){ num[i][k] = Nx ++; } } for(int i =0;i < Nx; i++){ g[i].clear(); } for(int i = 0;i < n; i++){ for(int k = 0; k < m; k++){ if((i+k) %2 == 1 && mp[i][k] == '*'){ for(int j = 0; j < 4;j++){ int x = i+ MOVE[j][0], y = k + MOVE[j][1]; if(0 <= x && x < n && 0 <= y && y < m && mp[x][y] == '*'){ g[num[i][k]].push_back(num[x][y]); } } } } } sum = 0; for(int i =0 ;i < n; i++){ for(int k= 0; k < m; k++){ if(mp[i][k] == '*') sum ++; } } if(sum == MaxMatch() * 2){ printf("YES "); }else{ printf("NO "); } } }
今天水了十多道图论题,脑袋好疼,虽然代码行数加起来也有一两千,但是都是水题,练了一天手速.....有了女朋友也不能放弃治疗啊..........
题意:m个长度为n的2进制数,可能某一位是*代替(代表*=1和*=0都被包含了)。要求用最少的另外一些二进制数(也可以某一位被*代替)将原来的那些覆盖(且只能覆盖一次),且要求不能覆盖原本不存在的二进制数。
刚开始想直接对每个点连接连接大于这个点编号并且能够相连的,我以为这样就能保证连线不重复,但是,如果有1-2,2-3这样的连线的话2相当于被使用了两次,我犯的错误就是没有将点分成两部分。对二分图的理解有加深的一层,虽然是好久前就应该掌握的,希望亚洲区之前能过把图论弄得差不多。
这段时间有点浮躁焦虑,不想太多了,抱着失败的觉悟和奔向成功的目标再努力一次吧......
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> #include<map> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } map<int, int> mp; const int maxa = 2222; char str[maxa][11]; char chess[maxa][11]; int main(){ int n, m; while(scanf("%d%d", &n, &m), n+m){ mp.clear(); int num_chess = 0; for(int i = 0;i < m; i++){ scanf("%s", str[i]); int star = 0; for(int k =0;k < n; k++){ if(str[i][k] == '*'){ star = 1; str[i][k] = '0'; int aa = 0; for(int j =0; j < n; j++){ chess[num_chess][j] = str[i][j]; aa = aa*2 + str[i][j] - '0'; }//num_chess++; if(mp[aa] == 0){ mp[aa] = 1; num_chess++; } str[i][k] = '1'; aa = 0; for(int j =0; j < n; j++){ chess[num_chess][j] = str[i][j]; aa = aa*2 + str[i][j] - '0'; }//num_chess++; if(mp[aa] == 0){ mp[aa] = 1; num_chess++; } break; } } if(!star){ int aa = 0; for(int j =0; j < n; j++){ chess[num_chess][j] = str[i][j]; aa = aa*2 + str[i][j] - '0'; }//num_chess++; if(mp[aa] == 0){ mp[aa] = 1; num_chess++; } } } for(int i = 0 ; i < num_chess; i++){ g[i].clear(); } /*for(int i =0; i < num_chess; i++){ printf("%s ", chess[i]); }*/ for(int i = 0;i < num_chess; i++){ for(int k = 0; k < num_chess; k++){ int sum_def = 0; int ss =0; for(int j = 0; j < n; j++){ if(chess[i][j] == '1') ss++; if(chess[i][j] != chess[k][j]) sum_def ++; } if(ss %2 ==1 && sum_def == 1){ g[i].push_back(k); } } } Nx = num_chess; printf("%d ", num_chess -MaxMatch()); } }
题意:已知班级有g个女孩和b个男孩,所有女生之间都相互认识,所有男生之间也相互认识,给出m对关系表示哪个女孩与哪个男孩认识。现在要选择一些学生来组成一个团,使得里面所有人都认识,求此团最大人数。
这个题只要将没有关系的两个人连线,求最大点独立集就好,最大点独立集的求法是总点数减去最大匹配数
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } } return dis!=INF; } bool DFS(int u) { for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(!vst[v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa = 222; int G[maxa][maxa]; int main(){ int n, m, q; int cas = 1; while(scanf("%d%d%d", &n, &m, &q)!=EOF){ if(n == 0 && m == 0 && q == 0) return 0; for(int i = 1; i <= n; i++){ for(int k = 1; k <= m; k++){ G[i][k] = 1; } } while(q--){ int u, v; scanf("%d%d", &u, &v); G[u][v] = 0; } for(int i = 1;i <= n; i++){ g[i].clear(); for(int k = 1;k <= m; k++){ if(G[i][k]){ g[i].push_back(k); } } } Nx = n+1; printf("Case %d: %d ",cas++, n+m - MaxMatch()); } }