hdu 1045 Fire Net 二分图匹配 && HDU-1281-棋盘游戏

题意:任意两个个‘车’不能出现在同一行或同一列,当然如果他们中间有墙的话那就没有什么事,问最多能放多少个‘车’
代码+注释:
 1 //二分图最大匹配问题
 2 //难点在建图方面,如果这个图里面一道墙也没有,那么可以说就是在横坐标(1...n)和纵坐标(1...n)
 3 //中个挑选出来一个,那个点就是我们要放置炮台的地方,么个点只能用一次,这样就能保证正确性
 4 //现在现在里面有墙了,在横坐标方面那么看到一个墙就把横坐标的选择数加1,每次换行也加1
 5 //纵坐标也做相应处理,那么我们就可以得到两个集合,一个横坐标集合,一个纵坐标集合
 6 //我们现在就是从这两个集合中选取元素,集合中元素的意义和没有墙时候的一样
 7 //但是他们并不是随意搭配,只有从两个集合中拿去的两个值,在原图中出现的位置相同才可以搭边
 8 #include<stdio.h>
 9 #include<algorithm>
10 #include<string.h>
11 #include<iostream>
12 #include<queue>
13 using namespace std;
14 const int maxn=20;
15 char maps[maxn][maxn];
16 int link[maxn][maxn],used[maxn],id1[maxn][maxn],flag[maxn],id2[maxn][maxn];
17 int n,lcnt,rcnt;
18 bool dfs(int x)
19 {
20     for(int i=1;i<=lcnt;i++)
21     {
22         if(link[x][i] && !used[i])
23         {
24             used[i]=1;
25             if(flag[i]==0 || dfs(flag[i]))
26             {
27                 flag[i]=x;
28                 return 1;
29             }
30         }
31     }
32     return 0;
33 }
34 int match()
35 {
36     int ans=0;
37     memset(flag,0,sizeof(flag));
38     for(int i=1;i<=rcnt;++i)
39     {
40         memset(used,0,sizeof(used));
41         ans+=dfs(i);
42     }
43     return ans;
44 }
45 int main()
46 {
47     while(~scanf("%d",&n)&&n)
48     {
49         rcnt=lcnt=0;
50         memset(link,0,sizeof(link));
51         memset(id1,0,sizeof(id1));
52         memset(id2,0,sizeof(id2));
53         for(int i=1;i<=n;++i)
54             scanf("%s",maps[i]+1);
55         for(int i=1;i<=n;++i)
56         {
57             for(int j=1;j<=n;++j)
58             {
59                 if(maps[i][j]=='.')
60                 {
61                     if(j-1==0 || maps[i][j-1]=='X') rcnt++;
62                     id1[i][j]=rcnt;
63                 }
64             }
65         }
66         for(int j=1;j<=n;++j)
67         {
68             for(int i=1;i<=n;++i)
69             {
70                 if(maps[i][j]=='.')
71                 {
72                     if(i-1==0 || maps[i-1][j]=='X') lcnt++;
73                     id2[i][j]=lcnt;
74                 }
75             }
76         }
77         for(int i=1;i<=n;++i)
78         {
79             for(int j=1;j<=n;++j)
80             {
81                 link[id1[i][j]][id2[i][j]]=1;
82             }
83         }
84         printf("%d\n",match());
85     }
86     return 0;
87 }
View Code

 

HDU-1281-棋盘游戏:

题意:这道题黑心那个一道题可不是完全一样,这上面可是没有墙这个东西,所以就是明显的二分图最大匹配,一个集合是对应的列,另一个集合是行

一个匹配边在棋盘上面就是一个具体的位置(因为行和列已经确定而且每个点只能使用一次)

 

代码:

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<queue>
 6 using namespace std;
 7 const int maxn=1005;
 8 int match[maxn],visit[maxn],n,id1,id2,m,grap[maxn][maxn],w[maxn][maxn],w1[maxn][maxn],w2[maxn][maxn];
 9 int dfs_solve(int x)
10 {
11     for(int i=1;i<=id2;++i)
12     {
13         if(grap[x][i] && !visit[i])
14         {
15             visit[i]=1;
16             if(match[i]==0 || dfs_solve(match[i]))
17             {
18                 match[i]=x;
19                 return 1;
20             }
21         }
22     }
23     return 0;
24 }
25 int hungan()
26 {
27     memset(match,0,sizeof(match));
28     int sum=0;
29     for(int i=1;i<=id1;++i)
30     {
31         memset(visit,0,sizeof(visit));
32         sum+=dfs_solve(i);
33     }
34     return sum;
35 }
36 int main()
37 {
38     int n,m,k,e=0;
39     while(~scanf("%d%d%d",&n,&m,&k))
40     {
41         memset(grap,0,sizeof(grap));
42         while(k--)
43         {
44             int a,b;
45             scanf("%d%d",&a,&b);
46             grap[a][b]=1;
47         }
48         id1=n;  //这个题目和A题的区别就在于,本题目上的一句话“注意不能放车的地方不影响车的互相攻击”
49         id2=m;  //所以这个题目可以看做简单的(1..n)和(1...m)的匹配
50         int ans=hungan();
51         int temp=0;
52         for(int i=1;i<=n;++i)
53         {
54             for(int j=1;j<=m;++j)
55             {
56                 if(grap[i][j])
57                 {
58                     grap[i][j]=0;
59                     int su=hungan();
60                     if(su<ans) temp++;//,printf("%d\n",su);
61                     grap[i][j]=1;
62                 }
63             }
64         }
65         printf("Board %d have %d important blanks for %d chessmen.\n",++e,temp,ans);
66     }
67     return 0;
68 }
View Code

 

转载于:https://www.cnblogs.com/kongbursi-2292702937/p/11494301.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值