HDU5090--Game with Pearls 二分图匹配 (匈牙利算法)
题意:给N个容器,每个容器里有一定数目的珍珠,现在Jerry开始在管子上面再放一些珍珠,放上的珍珠数必须是K的倍数,可以不放。最后将容器排序,如果可以做到第i个容器上面有i个珍珠,则Jerry胜出,反之Tom胜出。
思路:数据比较小,所以我是水过的,模拟过程 + 贪心就能过。但正解是二分图匹配,之前没接触过。
二分图匹配:解释一下第二组样例,k = 2;
从左向右,每一个能够匹配 i 的(a),就去掉 i 周围其他的边,然后再也去掉a能指向的边,计算一下共有几个能匹配的,如果是n,则Jerry胜,否则Tom胜;
水过的代码
1 ///水过的代码
2 #include <iostream>
3 #include <cmath>
4 #include <cstdio>
5 #include <cstring>
6 #include <cstdlib>
7 #include <string>
8 #include <sstream>
9 #include <algorithm>
10 #define Max 2147483647
11 #define INF 0x7fffffff
12 #define N 90010
13 #define ll long long
14 #define mem(a,b) memset(a,b,sizeof(a))
15 #define repu(i, a, b) for(int i = (a); i < (b); i++)
16 const double PI=-acos(-1.0);
17 using namespace std;
18 int a[N];
19 int main()
20 {
21 int n,T,k;
22 cin>>T;
23 while(T--)
24 {
25 cin>>n>>k;
26 repu(i,1,1+n)
27 cin>>a[i];
28 sort(a+1,a+1+n);
29 int ok = -1,i=1;
30 while(i<=n)
31 {
32 if(a[i]>i)
33 {
34 ok = 1;
35 break;
36 }
37 else if(a[i]<i)
38 {
39 a[i]+=k;
40 sort(a+1,a+1+n);
41 continue;
42 }
43 else
44 i++;
45 }
46 if(ok==1)
47 cout<<"Tom\n";
48 else
49 cout<<"Jerry\n";
50 }
51 return 0;
52 }
带权值的二分图匹配(改编下列某大神的代码):
1 ///http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82360#problem/B
2 #include <iostream>
3 #include <cmath>
4 #include <cstdio>
5 #include <cstring>
6 #include <cstdlib>
7 #include <string>
8 #include <sstream>
9 #include <algorithm>
10 #define Max 2147483647
11 #define INF 0x7fffffff
12 #define N 901
13 #define ll long long
14 #define mem(a,b) memset(a,b,sizeof(a))
15 #define repu(i, a, b) for(int i = (a); i < (b); i++)
16 using namespace std;
17 int g[N][N],vis[N],march[N],mat[N];
18 int n;
19 struct S
20 {
21 int val,v;
22 bool operator < (const S& s ) const
23 {
24 return val > s.val;
25 }
26 } p[N];
27 int dfs( int u )
28 {
29 for( int v = 1 ; v <= n ; v++ ) ///考虑所有 Yi 顶点 v
30 {
31 if(g[u][v]&&!vis[v]) ///v 与 u 邻接,且没有访问过
32 {
33 vis[v] = 1;///如果 v 没有匹配,或者 v 已经匹配了,但从 march[v]出发可以找到一条增广路
34 if(march[v] == -1 || dfs(march[v])) ///注意如果前一个条件成立,则不会递归调用
35 {
36 march[v] = u; ///把 v 匹配给 u
37 return 1; ///找到可增广路
38 }
39 }
40 }
41 mat[u] = 0;///如果不存在从u出发的增广路
42 return 0 ;
43 }
44
45 void MaxMatch( ) ///求二部图最大匹配的匈牙利算法
46 {
47 int res = 0; ///所求得的最大匹配
48 for(int i = 1 ; i <= n ; i++)
49 {
50 memset(vis , 0 , sizeof(vis)) ;
51 int u = p[i].v;///按照排好的权值一个个寻找匹配点
52 res += dfs(u);
53 }
54 ///res是能够匹配的个数
55 repu(i,1,n+1)
56 {
57 int t = march[i];///在dfs中是把v匹配给u,因此需要进一步转化
58 mat[t] = i;
59 }
60 for(int i = 1; i < 1+n; i++)
61 if(i==1)
62 printf("%d", mat[i]);
63 else
64 printf(" %d", mat[i]);
65 }
66 int main()
67 {
68 int a,b,m;
69 scanf("%d",&n);
70 memset(g,0,sizeof(g));
71 memset(march,-1,sizeof(march));
72 memset(mat,0,sizeof(mat));
73 repu(i,1,1+n)
74 {
75 scanf("%d",&a);
76 p[i].val = a;
77 p[i].v = i;
78 }
79 sort(p+1,p+1+n);///按照权值排序
80 repu(i,1,1+n)
81 {
82 scanf("%d",&m);
83 repu(j,0,m)
84 {
85 scanf("%d",&b);
86 g[i][b] = 1;
87 }
88 }
89 MaxMatch();
90 return 0;
91 }
二分图匹配的代码(某个大神的代码,先留着):
View Code
POJ1469是一个裸的二分图匹配,有p个课程,n个学生,求是否能让每个课程都有学生。
1 ///转自:http://blog.csdn.net/hackbuteer1/article/details/7398008
2 /*==================================================*\
3 | 二分图匹配(匈牙利算法DFS 实现)
4 | INIT: g[][]邻接矩阵;
5 | 优点:实现简洁容易理解,适用于稠密图,DFS找增广路快。
6 | 找一条增广路的复杂度为O(E),最多找V条增广路,故时间复杂度为O(VE)
7 ==================================================*/
8 #include<stdio.h>
9 #include<memory.h>
10 bool g[110][310]; ///邻接矩阵,true代表有边相连
11 bool flag,visit[310]; ///记录V2中的某个点是否被搜索过
12 int match[310]; ///记录与V2中的点匹配的点的编号
13 int p,n; ///二分图中左边、右边集合中顶点的数目
14
15 /// 匈牙利算法
16 bool dfs(int u)
17 {
18 for (int i = 1; i <= n; ++i)
19 {
20 if (g[u][i] && !visit[i]) ///如果节点i与u相邻并且未被查找过
21 {
22 visit[i] = true; ///标记i为已查找过
23 if (match[i] == -1 || dfs(match[i])) ///如果i未在前一个匹配M中,或者i在匹配M中,但是从与i相邻的节点出发可以有增广路径
24 {
25 match[i] = u; ///记录查找成功记录,更新匹配M(即“取反”)
26 return true; ///返回查找成功
27 }
28 }
29 }
30 return false;
31 }
32
33 int main(void)
34 {
35 int i,j,k,t,v,ans;
36 scanf("%d",&t);
37 while (t--)
38 {
39 scanf("%d %d", &p, &n);
40 for (i = 1; i <= p; i++)
41 {
42 for (j = 1; j <= n; j++)
43 g[i][j] = false;
44 }
45 for (i = 1; i <= n; i++)
46 match[i] = -1;
47 flag = true;
48 for (i = 1; i <= p; i++)
49 {
50 scanf("%d",&k);
51 if (k == 0)
52 flag = false;
53 while (k--)
54 {
55 scanf("%d",&v);
56 g[i][v] = true;
57 }
58 }
59 if (flag)
60 {
61 ans = 0;
62 for (i = 1; i <= p; i++)
63 {
64 memset(visit,false,sizeof(visit)); ///清空上次搜索时的标记
65 if(dfs(i)) ///从节点i尝试扩展
66 ans++;
67 }
68 if (ans == p)
69 puts("YES");
70 else
71 puts("NO");
72 }
73 else
74 puts("NO");
75 }
76 return 0;
77 }
人生就像心电图,想要一帆风顺,除非game-over