额,累死了,,快十天了没更新博客啦,这些天一直在做二分匹配,截止到刚才终于把hdu Index By Type里面的match做完啦。。好吧,一题一题开始说。

http://acm.hdu.edu.cn/showproblem.php?pid=2236

无题II

一般遇到使最大最小差值最小的问题,要想到二分答案,然后枚举下限,对于每一种情况判断是否可行。

因为每行没列都选一个,所以用到二分匹配,行在A中,列在B中,这样每一个数都代表从A到B的一条边。

然后判断在这样的一种情况下,能否找得到一组完备匹配。

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 105
 5 int map[N][N],n,used[N];
 6 bool vis[N][N],visit[N];
 7 int s[10005];
 8 bool getnum(int i)
 9 {
10     int j;
11     for(j=1;j<=n;j++)
12     {
13         if(vis[i][j] && !visit[j])
14         {
15             visit[j]=1;
16             if(used[j]==-1 || getnum(used[j]))
17             {
18                 used[j]=i;
19                 return 1;
20             }
21         }
22     }
23     return 0;
24 }
25 bool Match(int l,int r)
26 {
27     int i,j,count;
28     memset(vis,0,sizeof(vis));
29     for(i=1;i<=n;i++)
30     {
31         for(j=1;j<=n;j++)
32         {
33             if(map[i][j]>=l && map[i][j]<=r) vis[i][j]=1;
34         }
35     }
36     count=0;
37     memset(used,-1,sizeof(used));
38     for(i=1;i<=n;i++)
39     {
40         memset(visit,0,sizeof(visit));
41         if(getnum(i)) count++;
42     }
43     if(count==n) return 1;
44     return 0;
45 }
46 int cmp(const void *a,const void *b)
47 {
48     return *(int *)a - *(int *)b;
49 }
50 int main()
51 {
52     int i,j,ncase,Dnum,k;
53     int right,left,mid,ans;
54     scanf("%d",&ncase);
55     while(ncase--)
56     {
57         scanf("%d",&n);
58         k=0;
59         for(i=1;i<=n;i++)
60             for(j=1;j<=n;j++)
61             {
62                 scanf("%d",&map[i][j]);
63                 s[++k]=map[i][j];
64             }
65         qsort(s+1,n*n,sizeof(s[1]),cmp);
66         k=1;
67         for(i=2;i<=n*n;i++)
68             if(s[i]!=s[i-1]) s[++k]=s[i];
69         Dnum=s[k]-s[1];
70         left=0;right=Dnum;
71         while(left<=right)
72         {
73             mid=(left+right)/2;
74             for(i=1;s[i]+mid<=s[k];i++)
75             {
76                 if(Match(s[i],s[i]+mid)) break;
77             }
78             if( i<=k && s[i]+mid<=s[k])
79             {
80                 ans=mid;
81                 right=mid-1;
82             }
83             else left=mid+1;
84         }
85         printf("%d\n",ans);
86     }
87     return 0;
88 }

http://acm.hdu.edu.cn/showproblem.php?pid=1533

Going Home

很裸的一个km,n个人回到n个房子里面,两点之间的权值是他们的曼哈顿距离,让你求 每个人都回到房子里所需走的距离和最小,一般km都是求最大权值和,所以可以把边权取相反数,然后km,之后求得的值再取相反数。

View Code
  1 # include<stdio.h>
  2 # include<string.h>
  3 # include<stdlib.h>
  4 # define N 105
  5 # define INF 0xfffffff
  6 int n,k,m;
  7 int map[N][N];
  8 struct node{
  9     int x,y;
 10 }s1[N],s2[N];
 11 int lx[N],ly[N];
 12 bool visx[N],visy[N];
 13 int slock[N],used[N];
 14 int dis(int i,int j)
 15 {
 16     int ans,num;
 17     num=s1[i].x-s2[j].x;
 18     if(num<0) num=-num;
 19     ans=s1[i].y-s2[j].y;
 20     if(ans<0) ans=-ans;
 21     return ans+num;
 22 }
 23 int Min(int a,int b)
 24 {
 25     return a<b?a:b;
 26 }
 27 bool find(int x)
 28 {
 29     int j,t;
 30     visx[x]=1;
 31     for(j=1;j<=k;j++)
 32     {
 33         if(visy[j]) continue;
 34         t=lx[x]+ly[j]-map[x][j];
 35         if(t==0)
 36         {
 37             visy[j]=1;
 38             if(used[j]==-1 || find(used[j]))
 39             {
 40                 used[j]=x;
 41                 return 1;
 42             }
 43         }
 44         else if(t<slock[j]) slock[j]=t;
 45     }
 46     return 0;
 47 }
 48 void KM()
 49 {
 50     int i,j,d;
 51     memset(ly,0,sizeof(ly));
 52     memset(used,-1,sizeof(used));
 53     for(i=1;i<=k;i++)
 54     {
 55         for(j=1;j<=k;j++)
 56             slock[j]=INF;
 57         for(;;)
 58         {
 59             memset(visx,0,sizeof(visx));
 60             memset(visy,0,sizeof(visy));
 61             if(find(i)) break;
 62             d=INF;
 63             for(j=1;j<=k;j++)
 64                 if(!visy[j]) d=Min(d,slock[j]);
 65 
 66             for(j=1;j<=k;j++)
 67                 if(visx[j]) lx[j]-=d;
 68 
 69             for(j=1;j<=k;j++)
 70                 if(visy[j]) ly[j]+=d;
 71                 else slock[j]-=d;
 72         }
 73     }
 74 }
 75 int main()
 76 {
 77     int i,j,k1,k2,sum;
 78     char ch[105];
 79     while(scanf("%d%d",&n,&m)!=EOF)
 80     {
 81         if(n==0 && m==0) break;
 82         k1=k2=0;
 83         for(i=0;i<n;i++)
 84         {
 85             scanf("%s",ch);
 86             for(j=0;j<m;j++)
 87             {
 88                 if(ch[j]=='H') 
 89                 {
 90                     s1[++k1].x=i;
 91                     s1[k1].y=j;
 92                 }
 93                 else if(ch[j]=='m')
 94                 {
 95                     s2[++k2].x=i;
 96                     s2[k2].y=j;
 97                 }
 98             }
 99         }
100         k=k1;
101         for(i=1;i<=k;i++)
102         {
103             lx[i]=-INF;
104             for(j=1;j<=k;j++)
105             {
106                 map[i][j]=-1*dis(i,j);
107                 if(map[i][j]>lx[i]) lx[i]=map[i][j];
108             }
109         }
110         KM();
111         sum=0;
112         for(j=1;j<=k;j++)
113             sum+=map[used[j]][j];
114         printf("%d\n",-sum);
115     }
116     return 0;
117 }

http://acm.hdu.edu.cn/showproblem.php?pid=2255

奔小康赚大钱

还是一个km,直接模板,没什么说的了。

 

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 305
 5 # define INF 0xfffffff
 6 int n;
 7 int map[N][N];
 8 int lx[N],ly[N];
 9 bool visx[N],visy[N];
10 int slock[N],used[N];
11 bool find(int x)
12 {
13     int j,t;
14     visx[x]=1;
15     for(j=1;j<=n;j++)
16     {
17         if(visy[j]) continue;
18         t=lx[x]+ly[j]-map[x][j];
19         if(t==0)
20         {
21             visy[j]=1;
22             if(used[j]==-1 || find(used[j]))
23             {
24                 used[j]=x;
25                 return 1;
26             }
27         }
28         else if(t<slock[j]) slock[j]=t;
29     }
30     return 0;
31 }
32 int Min(int a,int b)
33 {
34     return a<b?a:b;
35 }
36 void KM()
37 {
38     int i,j,d;
39     memset(ly,0,sizeof(ly));
40     memset(used,-1,sizeof(used));
41     for(i=1;i<=n;i++)
42     {
43         for(j=1;j<=n;j++) slock[j]=INF;
44         for(;;)
45         {
46             memset(visx,0,sizeof(visx));
47             memset(visy,0,sizeof(visy));
48             if(find(i)) break;
49             d=INF;
50             for(j=1;j<=n;j++)
51                 if(!visy[j]) d=Min(d,slock[j]);
52             for(j=1;j<=n;j++)
53                 if(visx[j]) lx[j]-=d;
54             for(j=1;j<=n;j++)
55                 if(visy[j]) ly[j]+=d;
56                 else slock[j]-=d;
57         }
58     }
59 }
60 int main()
61 {
62     int i,j,sum;
63     while(scanf("%d",&n)!=EOF)
64     {
65             for(i=1;i<=n;i++)
66             {
67                 lx[i]=0;
68                 for(j=1;j<=n;j++)
69                 {
70                     scanf("%d",&map[i][j]);
71                     if(map[i][j]>lx[i]) lx[i]=map[i][j];
72                 }
73             }
74             KM();
75             sum=0;
76             for(j=1;j<=n;j++)
77                 sum+=map[used[j]][j];
78             printf("%d\n",sum);
79     }
80     return 0;
81 }

 

http://acm.hdu.edu.cn/showproblem.php?pid=1083

Courses

有P门课程,N位学生,每一位学生可以代表一门他已经访问过的课程,问最后每一门课是否都有学生代表。

二分匹配,判断最大匹配是否为P。

 

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 305
 5 # define P 105
 6 bool map[P][N],vis[N];
 7 int used[N];
 8 int n,p;
 9 bool getnum(int i)
10 {
11     int j;
12     for(j=1;j<=n;j++)
13     {
14         if(!vis[j] && map[i][j])
15         {
16             vis[j]=1;
17             if(used[j]==-1 || getnum(used[j]))
18             {
19                 used[j]=i;
20                 return 1;
21             }
22         }
23     }
24     return 0;
25 }
26 int main()
27 {
28     int i,j,ncase,num,ans;
29     scanf("%d",&ncase);
30     while(ncase--)
31     {
32         scanf("%d%d",&p,&n);
33         memset(map,0,sizeof(map));
34         for(i=1;i<=p;i++)
35         {
36             scanf("%d",&num);
37             for(j=1;j<=num;j++)
38             {
39                 scanf("%d",&ans);
40                 map[i][ans]=1;
41             }
42         }
43         if(p>n) {printf("NO\n");continue;}
44         memset(used,-1,sizeof(used));
45         for(i=1;i<=p;i++)
46         {
47             memset(vis,0,sizeof(vis));
48             if(!getnum(i)) break;
49         }
50         if(i==p+1) printf("YES\n");
51         else printf("NO\n");
52     }
53     return 0;
54 }

 

 http://acm.hdu.edu.cn/showproblem.php?pid=1281

棋盘游戏

因为车对同一行同一列的相互攻击,所以每一行每一列只能放一个棋子。

求出最大匹配后,因为要判断每一点是否为关键点,枚举最大匹配中的每一点,把他去掉,再求最大匹配数看是否和原来的相等,如果相等,那该点就不是一个关键点,否则是一个关键点。

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 105
 5 int n,m,K;
 6 bool map[N][N],vis[N];
 7 int used[N],ans[N];
 8 struct node{
 9     int x,y;
10 }s[N*N];
11 bool getnum(int i)
12 {
13     int j;
14     for(j=1;j<=m;j++)
15     {
16         if(!vis[j] && map[i][j])
17         {
18             vis[j]=1;
19             if(used[j]==-1 || getnum(used[j]))
20             {
21                 used[j]=i;
22                 return 1;
23             }
24         }
25     }
26     return 0;
27 }
28 int main()
29 {
30     int i,j,t=0,count,num,a,b,ans1;
31     while(scanf("%d%d%d",&n,&m,&K)!=EOF)
32     {
33         t++;
34         memset(map,0,sizeof(map));
35         for(i=1;i<=K;i++)
36         {
37             scanf("%d%d",&a,&b);
38             map[a][b]=1;
39             s[i].x=a;
40             s[i].y=b;
41         }
42         memset(used,-1,sizeof(used));
43         count=0;
44         for(i=1;i<=n;i++)
45         {
46             memset(vis,0,sizeof(vis));
47             if(getnum(i)) count++;
48         }
49         num=0;
50         for(i=1;i<=K;i++)
51         {
52             a=s[i].x;
53             b=s[i].y;
54             if(used[b]==a)
55             {
56                 for(j=1;j<=m;j++)
57                     ans[j]=used[j];
58                 map[a][b]=0;
59                 memset(used,-1,sizeof(used));
60                 ans1=0;
61                 for(j=1;j<=n;j++)
62                 {
63                     memset(vis,0,sizeof(vis));
64                     if(getnum(j)) ans1++;
65                 }
66                 if(ans1<count) num++;
67                 map[a][b]=1;
68                 for(j=1;j<=m;j++)
69                     used[j]=ans[j];
70             }
71         }
72     printf("Board %d have %d important blanks for %d chessmen.\n",t,num,count);
73     }
74     return 0;
75 }

 

http://acm.hdu.edu.cn/showproblem.php?pid=1498

50 years, 50 colors

扎气球,每一次可以扎破同一行或者同一列相同颜色的气球。对每一种颜色问在扎了k次之后能否把该颜色的气球全扎破。二分匹配,对于每一种颜色,还是把行放在A集合中,列放在B集合中,然后求最小点集覆盖。

最小点集覆盖=最大匹配。

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 105
 5 int n,k;
 6 bool vis[N],map[N][N];
 7 int used[N],num[55];
 8 struct node{
 9     int x,y;
10 }s[55][10005];
11 bool getnum(int i)
12 {
13     int j;
14     for(j=1;j<=n;j++)
15     {
16         if(!vis[j] && map[i][j])
17         {
18             vis[j]=1;
19             if(used[j]==-1 || getnum(used[j]))
20             {
21                 used[j]=i;
22                 return 1;
23             }
24         }
25     }
26     return 0;
27 }
28 int main()
29 {
30     int i,j,kk,mm[N],ans,a,b,count;
31     while(scanf("%d%d",&n,&k)!=EOF)
32     {
33         if(n==0 && k==0) break;
34         memset(num,0,sizeof(num));
35          for(i=1;i<=n;i++)
36          {
37              for(j=1;j<=n;j++)
38              {
39                  scanf("%d",&ans);
40                  num[ans]++;
41                  s[ans][num[ans]].x=i;
42                  s[ans][num[ans]].y=j;
43              }
44          }
45          kk=0;
46          for(i=1;i<=50;i++)
47          {
48              if(num[i]<=k) continue;
49              memset(map,0,sizeof(map));
50              for(j=1;j<=num[i];j++)
51              {
52                  a=s[i][j].x;
53                  b=s[i][j].y;
54                  map[a][b]=1;
55              }
56              memset(used,-1,sizeof(used));
57              count=0;
58              for(j=1;j<=n;j++)
59              {
60                  memset(vis,0,sizeof(vis));
61                  if(getnum(j)) count++;
62              }
63              if(count>k)  mm[++kk]=i;
64          }
65          if(kk==0) printf("-1\n");
66          else
67          {
68              printf("%d",mm[1]);
69              for(i=2;i<=kk;i++)
70                  printf(" %d",mm[i]);
71              printf("\n");
72          }
73     }
74     return 0;
75 }

 

http://acm.hdu.edu.cn/showproblem.php?pid=3605

Escape

二分图的多重匹配,把原来的used数组改成二维的即可。

由于一个vis数组开大了,各种超时。。

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 100005
 5 int num[12];
 6 int used[12][N],ans[12];
 7 bool map[N][12],vis[12];
 8 int n,m;
 9 bool getnum(int i)
10 {
11     int j,k;
12     for(j=1;j<=m;j++)
13     {
14         if(!vis[j] && map[i][j])
15         {
16             vis[j]=1;
17             if(num[j]<ans[j])
18             {
19                 num[j]++;
20                 used[j][num[j]]=i;
21                 return 1;
22             }
23             else 
24             {
25                 for(k=1;k<=ans[j];k++)
26                 {
27                     if(getnum(used[j][k])) 
28                     {
29                         used[j][k]=i;
30                         return 1;
31                     }
32                 }
33             }
34         }
35     }
36     return 0;
37 }
38 int main()
39 {
40     int i,j,sum;
41     while(scanf("%d%d",&n,&m)!=EOF)
42     {
43         for(i=1;i<=n;i++)
44             for(j=1;j<=m;j++)
45                 scanf("%d",&map[i][j]);
46             sum=0;
47             for(i=1;i<=m;i++)
48             {
49                 scanf("%d",&ans[i]);
50                 sum+=ans[i];
51             }
52             if(sum<n) {printf("NO\n");continue;}
53             memset(used,-1,sizeof(used));
54             memset(num,0,sizeof(num));
55             for(i=1;i<=n;i++)
56             {
57                 memset(vis,0,sizeof(vis));
58                 if(!getnum(i)) break;
59             }
60             if(i<=n) printf("NO\n");
61             else printf("YES\n");
62     }
63     return 0;
64 }

 

http://acm.hdu.edu.cn/showproblem.php?pid=1151

Air Raid

//路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点

最小路径覆盖=顶点数-最大匹配

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 125
 5 bool map[N][N],vis[N];
 6 int used[N];
 7 int n,m;
 8 bool getnum(int u)
 9 {
10     int i;
11     for(i=1;i<=n;i++)
12     {
13         if(!vis[i] && map[u][i])
14         {
15             vis[i]=1;
16             if(used[i]==-1 || getnum(used[i]))
17             {
18                 used[i]=u;
19                 return 1;
20             }
21         }
22     }
23     return 0;
24 }
25 int main()
26 {
27     int i,ncase,count;
28     int a,b;
29     scanf("%d",&ncase);
30     while(ncase--)
31     {
32         scanf("%d%d",&n,&m);
33         memset(map,0,sizeof(map));
34         while(m--)
35         {
36             scanf("%d%d",&a,&b);
37             map[a][b]=1;
38         }
39         memset(used,-1,sizeof(used));
40         count=0;
41         for(i=1;i<=n;i++)
42         {
43             memset(vis,0,sizeof(vis));
44             if(getnum(i)) count++;
45         }
46         printf("%d\n",n-count);
47     }
48     return 0;
49 }

 

http://acm.hdu.edu.cn/showproblem.php?pid=1669

Jamie's Contact Groups

二分答案+多重匹配,开始用邻接表写的,一直WA,最后改成邻接矩阵竟然对了,不知道用邻接表为什么会错,很是不解。

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 1005
 5 # define M 505
 6 int n,m,mid;
 7 int used[M][N],Num[M];
 8 bool vis[M],map[N][M];
 9 bool getnum(int u)
10 {
11     int j,v;
12     for(j=0;j<m;j++)
13     {
14         v=j;
15         if(!map[u][v]) continue;
16         if(vis[v]) continue;
17         vis[v]=1;
18         if(Num[v]<mid)
19         {
20             Num[v]++;
21             used[v][Num[v]]=u;
22             return 1;
23         }
24         for(j=1;j<=Num[v];j++)
25         {
26             if(getnum(used[v][j])) 
27             {
28                 used[v][j]=u;
29                 return 1;
30             }
31         }
32     }
33     return 0;
34 }
35 int main()
36 {
37     int i,j;
38     int flag,num,ans;
39     int l,r;
40     char str[20000];
41     while(scanf("%d%d",&n,&m)!=EOF)
42     {
43         if(n==0 && m==0) break;
44         memset(map,0,sizeof(map));
45         for(i=0;i<n;i++)
46         {
47             scanf("%s",str);
48             gets(str);
49             flag=0;
50             for(j=0;str[j];j++)
51             {
52                 if(str[j]>='0' && str[j]<='9' && flag==0)
53                 {
54                     num=str[j]-'0';
55                     flag=1;
56                 }
57                 else if(str[j]>='0' && str[j]<='9')
58                 {
59                     num*=10;
60                     num+=str[j]-'0';
61                 }
62                 else if(str[j]==' ')
63                 {
64                     if(flag==1) map[i][num]=1;
65                     flag=0;
66                 }        
67             }
68                 if(flag==1) map[i][num]=1;
69         }
70         l=n/m;
71         if(l*m!=n) l++;
72         r=n;
73         while(l<=r)
74         {
75             mid=(l+r)/2;
76             memset(Num,0,sizeof(Num));
77             for(i=0;i<n;i++)
78             {
79                 memset(vis,0,sizeof(vis));
80                 if(!getnum(i)) break;
81             }
82             if(i==n) {ans=mid;r=mid-1;}
83             else l=mid+1;
84         }
85         printf("%d\n",ans);
86     }
87     return 0;
88 }

 

http://acm.hdu.edu.cn/showproblem.php?pid=2413

 

Against Mammoths

我也是用二分答案做的,但是有一组例子都跑不出来。。。

1 1

0 40000 40000 39999

40000

结果应该是1600040000。

难道是我水过了????

 

 

 

 

 

 

 

 

 

 

 

posted on 2012-07-18 18:25  奋斗青春  阅读(792)  评论(0编辑  收藏  举报