HDU 多校联合练习赛2 Warm up 2 二分图匹配
Warm up 2
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 656 Accepted Submission(s): 329
Problem Description
Some 1×2 dominoes are placed on a plane. Each dominoe is placed either horizontally or vertically. It's guaranteed the dominoes in the same direction are not overlapped, but horizontal and vertical dominoes may overlap with each other. You task is to remove some dominoes, so that the remaining dominoes do not overlap with each other. Now, tell me the maximum number of dominoes left on the board.
Input
There are multiple input cases.
The first line of each case are 2 integers: n(1 <= n <= 1000), m(1 <= m <= 1000), indicating the number of horizontal and vertical dominoes.
Then n lines follow, each line contains 2 integers x (0 <= x <= 100) and y (0 <= y <= 100), indicating the position of a horizontal dominoe. The dominoe occupies the grids of (x, y) and (x + 1, y).
Then m lines follow, each line contains 2 integers x (0 <= x <= 100) and y (0 <= y <= 100), indicating the position of a horizontal dominoe. The dominoe occupies the grids of (x, y) and (x, y + 1).
Input ends with n = 0 and m = 0.
The first line of each case are 2 integers: n(1 <= n <= 1000), m(1 <= m <= 1000), indicating the number of horizontal and vertical dominoes.
Then n lines follow, each line contains 2 integers x (0 <= x <= 100) and y (0 <= y <= 100), indicating the position of a horizontal dominoe. The dominoe occupies the grids of (x, y) and (x + 1, y).
Then m lines follow, each line contains 2 integers x (0 <= x <= 100) and y (0 <= y <= 100), indicating the position of a horizontal dominoe. The dominoe occupies the grids of (x, y) and (x, y + 1).
Input ends with n = 0 and m = 0.
Output
For each test case, output the maximum number of remaining dominoes in a line.
Sample Input
2 3
0 0
0 3
0 1
1 1
1 3
4 5
0 1
0 2
3 1
2 2
0 0
1 0
2 0
4 1
3 2
0 0
Sample Output
4
6
Source
Recommend
zhuyuanchen520
题解:
原来是我建图不会建。。。果然是基础功不扎实啊。。
原来就是个普通的最大独立集。 最大独立集的定义就是所选取的点集合中,任意两条边都不相连。 又因为题目中说横着的不会跟横着的相连,竖着的不会跟竖着的相连,所以。这是个相当标准的二分图。就是求X集合跟Y集合的最大独立集。
建造图时,X取的是那0到n-1个骨牌 Y取的是后面的0到m-1个骨牌。。。无语撒。。原来当初我2分图完全弄错了。。
这题解法好像很多。。什么搜索,贪心。。不说了。。。牢记不会建图的教训。。
我提供下我写的3份模板代码吧。。。。
第一份 33MS
#include <cstdio> #include <cstdlib> #include <cstring> #include <cstring> const int maxn=1111; int g[maxn][maxn]; int cx[maxn],cy[maxn],vst[maxn]; int nx,ny; int findpath(int u){ for(int v=0;v<ny;v++){ if(!vst[v]&&g[u][v]){ vst[v]=1; if(cy[v]==-1||findpath(cy[v])){ cy[v]=u,cx[u]=v; return 1; } } } return 0; } int MaxMatch(){ int ret=0; memset(cx,-1,sizeof(cx)); memset(cy,-1,sizeof(cy)); for(int i=0;i<nx;i++) if(cx[i]==-1){ memset(vst,0,sizeof(vst)); if(findpath(i)) ret++; } return ret; } struct node{ int x,y; }mx[maxn],my[maxn]; int main(){ //freopen("1009.in","r",stdin); int n,m; while(scanf("%d %d",&n,&m)&&n+m){ for(int i=0,a,b;i<n;i++){ scanf("%d %d",&a,&b); mx[i].x=a,mx[i].y=b; } for(int i=0,a,b;i<m;i++){ scanf("%d %d",&a,&b); my[i].x=a,my[i].y=b; } memset(g,0,sizeof(g)); for(int i=0,x1,y1;i<n;i++){ x1=mx[i].x,y1=mx[i].y; for(int j=0,x2,y2;j<m;j++){ x2=my[j].x,y2=my[j].y; if(x1==x2&&y1==y2 ||x1==x2&&y1==y2+1 ||x1+1==x2&&y1==y2 ||x1+1==x2&&y1==y2+1) g[i][j]=1; } } nx=n,ny=m; printf("%d\n",n+m-MaxMatch()); } return 0; }
第2份:15MS
#include <cstdlib> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #define clr(x,k) memset((x),(k),sizeof(x)) #define foreach(it,c) for(vi::iterator it = (c).begin();it != (c).end();++it) using namespace std; typedef vector<int> vi; const int maxn=1000; vector<int> gx[maxn]; int cx[maxn],cy[maxn],vst[maxn]; int nx,ny; int findpath_Vector(int u){ foreach(it,gx[u]){ if(!vst[*it]){ vst[*it]=1; if(cy[*it]==-1||findpath_Vector(cy[*it])){ cx[u]=*it; cy[*it]=u; return 1; } } } return 0; } int maxMatch_Vector(){ int ret=0; clr(cx,-1),clr(cy,-1); for(int i=0;i<nx;i++) if(cx[i]==-1){ clr(vst,0); if(findpath_Vector(i)) ret++; } return ret; } struct node{ int x,y; }mx[maxn],my[maxn]; int main(){ // freopen("1009.in","r",stdin); int n,m; while(scanf("%d %d",&n,&m)&&n+m){ for(int i=0,a,b;i<n;i++){ scanf("%d %d",&a,&b); mx[i].x=a,mx[i].y=b; } for(int i=0,a,b;i<m;i++){ scanf("%d %d",&a,&b); my[i].x=a,my[i].y=b; } for(int i=0;i<n;i++) gx[i].clear(); for(int i=0,x1,y1;i<n;i++){ x1=mx[i].x,y1=mx[i].y; for(int j=0,x2,y2;j<m;j++){ x2=my[j].x,y2=my[j].y; if(x1==x2&&y1==y2 ||x1==x2&&y1==y2+1 ||x1+1==x2&&y1==y2 ||x1+1==x2&&y1==y2+1) gx[i].push_back(j); } } nx=n,ny=m; printf("%d\n",n+m-maxMatch_Vector()); } return 0; }
第3份 15MS。 hy这个算法应该会快点的。可能是因为题目有点特殊,没有体现。
#include <cstdlib> #include <cstdio> #include <vector> #include <queue> #include <cstring> #include <iostream> #define clr(x,k) memset((x),(k),sizeof(x)) #define foreach(it,c) for(vi::iterator it = (c).begin();it != (c).end();++it) using namespace std; typedef vector<int> vi; const int INF=1<<28; const int maxn=1000; int cx[maxn],cy[maxn]; vi gx[maxn]; int dx[maxn],dy[maxn]; int dis,nx; int vst[maxn]; bool searchpath(){ queue<int> Q; dis=INF; clr(dx,-1),clr(dy,-1); for(int i=0;i<nx;i++){ if(cx[i]==-1) Q.push(i),dx[i]=0; } while(!Q.empty()){ int u=Q.front();Q.pop(); if(dx[u]>dis) break; foreach(it,gx[u]) if(dy[*it]==-1){ dy[*it]=dx[u]+1; if(cy[*it]==-1) dis=dy[*it]; else{ dx[cy[*it]]=dy[*it]+1; Q.push(cy[*it]); } } } return dis!=INF; } int hop_Findpath_Vector(int u){ foreach(it,gx[u]){ if(!vst[*it]&&dy[*it]==dx[u]+1){//说明这是一条增广路径。但还需判断 vst[*it]=1; if(cy[*it]!=-1&&dy[*it]==dis) //出现这种情况。说明不是增广路, 因为最后一条增路是 cy[v]==-1&&dy[v]==dis continue; if(cy[*it]==-1||hop_Findpath_Vector(cy[*it])){ cy[*it]=u,cx[u]=*it; return 1; } } } return 0; } int hopcroft_MaxMatch_Vector(){ int res=0; clr(cx,-1),clr(cy,-1); while(searchpath()){ clr(vst,0); for(int i=0;i<nx;i++){ if(cx[i]==-1){ res+=hop_Findpath_Vector(i); } } } return res; } struct node{ int x,y; }mx[maxn],my[maxn]; int main(){ //freopen("1009.in","r",stdin); int n,m; while(scanf("%d %d",&n,&m)&&n+m){ for(int i=0,a,b;i<n;i++){ scanf("%d %d",&a,&b); mx[i].x=a,mx[i].y=b; } for(int i=0,a,b;i<m;i++){ scanf("%d %d",&a,&b); my[i].x=a,my[i].y=b; } for(int i=0;i<n;i++) gx[i].clear(); for(int i=0,x1,y1;i<n;i++){ x1=mx[i].x,y1=mx[i].y; for(int j=0,x2,y2;j<m;j++){ x2=my[j].x,y2=my[j].y; if(x1==x2&&y1==y2 ||x1==x2&&y1==y2+1 ||x1+1==x2&&y1==y2 ||x1+1==x2&&y1==y2+1) gx[i].push_back(j); } } nx=n; printf("%d\n",n+m-hopcroft_MaxMatch_Vector()); } return 0; }
如果要达到0MS的话。估计要贪心一下了。