题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31898
代码:
暴力代码:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n,m,q; int main() { int t; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { scanf("%d%d%d",&n,&m,&q); int maps[105][105]; memset(maps,1,sizeof(maps)); /*for(int i=1;i<=100;i++) { for(int j=1;j<=100;j++) maps[i][j]=1; }*/ for(int i=0;i<q;i++) { int x,y; scanf("%d%d",&x,&y); maps[x][y]=0; } int ans=0; /*for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { printf("%d ",maps[i][j]); } printf("\n"); }*/ for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { if(maps[j][i]!=0) { ans++; break; } } } //printf("%d %d %d",ans,m,n); printf("Case %d: %d\n",cas,min(ans,min(m,n))); } }
暴力代码好像不对
虽然能AC。
3 3 4
2 1
2 3
3 1
3 3
匈牙利算法:
#include<stdio.h> #include<string.h> using namespace std; int maps[1005][1005]; int vis[1005]; int n,m,q; int marry[1005]; int judge(int u) { for(int i=1;i<=m;i++) { if(maps[u][i] || vis[i]==1) continue; vis[i]=1; if(!marry[i]||judge(marry[i])) { marry[i]=u; return 1; } } return 0; } int main() { int t; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { scanf("%d%d%d",&n,&m,&q); memset(maps,0,sizeof(maps)); memset(marry,0,sizeof(marry)); for(int i=0;i<q;i++) { int x,y; scanf("%d%d",&x,&y); maps[x][y]=1; } int ans=0; for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(judge(i)) ans++; } printf("Case %d: %d\n",cas,ans); } }
第二次自己打的代码:
#include<stdio.h> #include<string.h> using namespace std; int maps[105][105]; int book[105]; int n,m,q; int match[105]; int get(int x) { for(int i=1;i<=m;i++) // 从1到m { if(book[i]==0&&maps[x][i]==0) { book[i]=1; if(match[i]==0||get(match[i])) { match[i]=x; return 1; } } } return 0; } int main() { int t; scanf("%d",&t); for(int i=1;i<=t;i++) { memset(maps,0,sizeof(maps)); memset(match,0,sizeof(match)); scanf("%d%d%d",&n,&m,&q); for(int i=0;i<q;i++) { int x,y; scanf("%d%d",&x,&y); maps[x][y]=1; } int ans=0; for(int i=1;i<=n;i++) // 注意是从1到n (顾客人数) { memset(book,0,sizeof(book)); // 每找到一条增广路配对数加一(见分析) if(get(i)) ans++;<span style="white-space:pre"> </span> } printf("Case %d: %d\n",i,ans); } }
bool find(int x){ int i,j; for (j=1;j<=m;j++){ //扫描每个妹子 if (line[x][j]==true && used[j]==false) //如果有暧昧并且还没有标记过(这里标记的意思是这次查找曾试图改变过该妹子的归属问题,但是没有成功,所以就不用瞎费工夫了) { used[j]=1; if (girl[j]==0 || find(girl[j])) { //名花无主或者能腾出个位置来,这里使用递归 girl[j]=x; return true; } } } return false; }/ \
数据(题意不同)(题意是男女配对找最大配对数-----------为3)
1 1
1 2
2 2
2 3
3 1
分析:
增广路是
若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径(举例来说,有A、B集合,增广路由A中一个点通向B中一个点,再由B中这个点通向A中一个点……交替进行)。
找到以1为起点的增广路,1-1;说明1可以配对,ans++;
找到以2为起点的增广路,2-2;说明2可以配对,ans++;
找到以3为起点的增广路,3-1;说明3可以配对,但在这时要想实现3的配对,需要更改 以1为起点的增广路,
因为在此之前1与1是配对的。
此时,一共有三条增广路,所以答案为3.
/*还有就是
1 1
2 1
时也会出现一条增广路。所以会出现 if ( book[ i ]==0 )book[ i ]=1;
这样就满足了。好像不对呀。不对。
是找2的增广路时,(find(2))
i=1;used【1】=1;find(girl【1】)
i=1;此时已经used【1】=1;
i=2;line【1】【2】=false;return 0;
i=2;return 0;即此时找不到以2为起点的增广路。
*/