码迷,mamicode.com
首页 > 其他好文 > 详细

棋盘游戏(二分图匹配)

时间:2015-08-27 00:00:26      阅读:619      评论:0      收藏:0      [点我收藏+]

标签:

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1281

棋盘游戏

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3200    Accepted Submission(s): 1897


Problem Description
小 希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是 Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在 Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量 多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解 决这个问题么?
技术分享
 

 

Input
输入包含多组数据,
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
 

 

Output
对输入的每组数据,按照如下格式输出:
Board T have C important blanks for L chessmen.
 

 

Sample Input
3 3 4 1 2 1 3 2 1 2 2 3 3 4 1 2 1 3 2 1 3 2
 

 

Sample Output
Board 1 have 0 important blanks for 2 chessmen. Board 2 have 3 important blanks for 3 chessmen.
 

 

Author
Gardon
 

 

Source
 
题解: 这种题有一种特殊的建图方法,然后就可以将问题巧妙的转换成二分图匹配的问题,然后用匈牙利算法解题即可: 将没一行看成是左边一个点,没一列看成是右边的一个点,如果这个点可以放棋子的话,就将其横纵坐标之间建立一条双向边,然后寻找最大的二分图匹配(相当于是每一个横行和纵行都只有一个焦点,而且使得焦点总数最多) 但是这个题要注意要求的是重要点的个数,及如果去掉这个点会影响最后焦点总数的点,所以,每次去掉一条边做一边二分图匹配,看最后,如果对结果有影响,则重要点个数加一
下面介绍匈牙利算法:
二分图匹配的匈牙利算法: 条件,可以将结点分成左右两组,两组之间有边,同一组之间没有边,求一对一的匹配数最多有多少,如果对于任意一个树来说,可以通过黑白染色的方法将图中的结点分成两份
dfs 的算法思路: 对于左边任意一个点来说,找到一条增广路,注意是找到一条增广路就停止寻找(边的条数是奇数,而且是一条虚线开始,虚实向间的折线,以虚线结尾——实线是已经匹配上的线段,虚线表示未匹配)然后将这条增广路上的实线和虚线对调,这样就实现了匹配数加1,然后遍历左边的所有点,然后得到所有的增广路的条数就是最后的结果(因为每找到一条增广路就可以使得总匹配数加1)
也可以换种方式理解: 一个左边的人B去右边找朋友,如果他找到了一个没有匹配过的人,那么就直接和她做朋友,而如果这个人C有了一个朋友A了,那么就从这个朋友A开始用同样的方式看他还能不能找到其他的朋友,如果可以的话 ,让A去找其他的人做朋友,这样B就可以C做朋友了(可以这么想,如果A另外寻找的D仍已经匹配过了,就再看D可以找到一个未匹配的吗,如果D找到的E仍然是匹配过的就再看E是否可以和其他人做朋友,这样一直找下去,知道找到了一个可以换一个人做朋友的,然后依次换掉,这样最开始的
现在考虑如何去掉一条边,可以在边的结构体中加上一个bool 参数标记这条边是不是还在,详见代码
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 #define N 210
 5 struct Edge{
 6     int to;
 7     bool in;
 8     int next;
 9 }edge[N*N];
10 int head[N];
11 int Enct;
12 bool visited[N*N];
13 int link[N];
14 void init()
15 {
16     memset(head,-1,sizeof(head));
17     Enct = 0;
18 }
19 void add(int from , int to)
20 {
21     edge[Enct].to = to;
22     edge[Enct].next = head[from];
23     edge[Enct].in = true;
24     head[from] = Enct++;
25     edge[Enct].to = from;
26     edge[Enct].in = true;
27     edge[Enct].next = head[to];
28     head[to] = Enct++;
29 }
30 bool find(int u)
31 {
32     for(int i = head[u] ; i!=-1 ; i = edge[i].next)
33     {
34         if(edge[i].in ==false) continue;
35         int v = edge[i].to;
36         if(visited[v]) continue;
37         visited[v] = true;
38         if(link[v] == -1||find(link[v]))
39         {
40             link[v] = u;//回溯,每次都将边反转
41             //printf("%d ",link[v]);
42             return true;
43         }
44     }
45     return false;
46 }
47 int k;
48 int n;
49 int solve()
50 {
51     memset(link,-1,sizeof(link));
52     int res = 0;
53     for(int i = 1 ;i <= n ;i++)//注意点的编号是从1开始的
54     {
55         memset(visited,0,sizeof(visited));
56         visited[i] = true;
57         if(find(i)){ res++; 
58              //printf("%d ",link[i]);
59              //puts("");
60         }
61     }
62     return res;
63 }
64 int main()
65 {
66     int m;
67     int c = 0;
68     while(~scanf("%d%d%d",&n,&m,&k))
69     {
70         c++;
71         init();
72         for(int i = 0 ; i < k ;i++)
73         {
74             int x, y;
75             scanf("%d%d",&x,&y);
76             add(x,y+n);
77         }
78         int sum = solve();
79         int ans = 0 ;
80         for(int i = 0 ;i < k ; i++)
81         {
82             edge[i<<1|1].in = false;
83             edge[i<<1].in = false;
84             int tm = solve();
85             if(tm!=sum) ans++;
86             edge[i<<1|1].in = true;
87             edge[i<<1].in = true;
88         }
89         printf("Board %d have %d important blanks for %d chessmen.\n",c,ans,sum);
90     }
91     return 0;
92 }

 

 

棋盘游戏(二分图匹配)

标签:

原文地址:http://www.cnblogs.com/shanyr/p/4761748.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!