A ZOJ 1002
题意:放棋子,棋子横竖不能相见。
做法:直接暴力DFS就行了。n很小只有4
B HDU2444
题意:给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识;
现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多大?
做法:首先用BFS染色判断是否是二分图,相连的边异色,如果不是则直接NO就行了。然后跑一边匈牙利算法,最后问的是几对可以匹配成功,那答案输出的时候要除以2
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=250;
int n,m;
vector<int> g[maxn];
int col[maxn];
bool judge()
{
memset(col,-1,sizeof(col));
col[1]=1;
queue<int> que;
que.push(1);
while(!que.empty())
{
int u=que.front(); que.pop();
int next=1-col[u];
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(col[v]==-1)
{
col[v]=next;
que.push(v);
}
else
{
if(col[v]==col[u]) return 1;
}
}
}
return 0;
}
bool used[maxn];
int boy[maxn];
bool f(int u)
{
for(int i=0;i<g[u].size();++i)
{
int v=g[u][i];
if(used[v]) continue;
used[v]=1;
if(boy[v]==-1||f(boy[v]))
{
boy[v]=u;
return 1;
}
}
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;++i) g[i].clear();
for(int i=1;i<=m;++i)
{
int a,b;
scanf("%d%d",&a,&b);
g[a].push_back(b); g[b].push_back(a);
}
if(judge()) printf("No\n");
else
{
int ans=0;
memset(boy,-1,sizeof(boy));
for(int i=1;i<=n;++i)
{
memset(used,0,sizeof(used));
if(f(i)) ans++;
}
printf("%d\n",ans/2);
}
}
return 0;
}
HDU 1083
题意:有p门课程,n个学生,每个学生在一个
committee代表一门课程,求学生和课程的最大匹配,若最大匹配等于p,输出YES,否则输出NO。
做法:直接二分匹配上模板
HDU 1281
题意:中文题意
做法:建图是关键,把x看做一个集合,y看做一个集合(x,y)代表x可以连y。然后跑一边最大匹配,然后枚举所有边,如果跑出来的答案与第一次不一样就是关键点,
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
int n,m,k;
bool map[105][105];
struct node
{
int x,y;
}p[100*105];
int boy[150];
int used[150];
bool f(int u)
{
for(int i=1;i<=m;++i)
{
if(map[u][i]&&!used[i])
{
used[i]=1;
if(boy[i]==-1 || f(boy[i]))
{
boy[i]=u;
return 1;
}
}
}
return 0;
}
int pp()
{
memset(boy,-1,sizeof(boy));
int l=0;
for(int i=1;i<=n;++i)
{
memset(used,0,sizeof(used));
if(f(i)) l++;
}
return l;
}
int main()
{
int kiss=0;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
memset(map,0,sizeof(map));
for(int i=1;i<=k;++i)
{
scanf("%d%d",&p[i].x,&p[i].y);
map[p[i].x][p[i].y]=1;
}
int l=pp();
int flag=0;
for(int i=1;i<=k;++i)
{
map[p[i].x][p[i].y]=0;
int temp=pp();
if(temp!=l) flag++;
map[p[i].x][p[i].y]=1;
}
printf("Board %d have %d important blanks for %d chessmen.\n",++kiss,flag,l);
}
return 0;
}
HDU 2819
题意:交换图的某些行或者是某些列(可以都换),使得这个N*N的图对角线上全部都是1.
注意:
这里有一点需要说明,就是说题目的交换,其实是将原来图的某一行移到最后图的某一行,而不是指先交换两行,得到一个新图,再交换新图的两行。感觉这里比较坑。
这里先说明的一点就是,如果通过交换某些行没有办法的到解的话,那么只交换列 或者 既交换行又交换列 那也没办法得到解。这个可以用矩阵的秩来解释,所有的对角线都是1,所以也就是矩阵的秩就是N,所以秩小于N就无解。另外,根据矩阵的性质,任意交换矩阵的两行 或者 两列,矩阵的秩不变,也就保证了如果通过 只交换行 或 只交换列 无法得到解的话,那么其他交换形式也必然无解。
做法: 既然说是用二分图的最大匹配,那怎么构建二分图呢,我们构建的二分图,第一部分X表示的是横坐标,第二部分Y表示纵坐标,所以范围都是1~N,然后如果a[i][j]是1,那我们就从X的i向Y的j引一条边,那么这条边的含义就可以解释为可以将Y的第j列(因为Y表示的是列的集合)移到第i列,使得a[i][i]变成1,这样就相当于是第i行第i列就变成了1,也就是说对角线多了一个1。
因此我们求这个二分图的最大匹配(目的是为了让每一列只与X中的某一行匹配),这样来就形成了N条边,那我们只需要将所有匹配的边的右边(列) 和 左边(行)所在的列 交换,这样一来对角线上这一行就成了1.
上面也也正好提示了如果最大匹配是N,那就存在解,否则无解。
这里先说明的一点就是,如果通过交换某些行没有办法的到解的话,那么只交换列 或者 既交换行又交换列 那也没办法得到解。这个可以用矩阵的秩来解释,所有的对角线都是1,所以也就是矩阵的秩就是N,所以秩小于N就无解。另外,根据矩阵的性质,任意交换矩阵的两行 或者 两列,矩阵的秩不变,也就保证了如果通过 只交换行 或 只交换列 无法得到解的话,那么其他交换形式也必然无解。
做法: 既然说是用二分图的最大匹配,那怎么构建二分图呢,我们构建的二分图,第一部分X表示的是横坐标,第二部分Y表示纵坐标,所以范围都是1~N,然后如果a[i][j]是1,那我们就从X的i向Y的j引一条边,那么这条边的含义就可以解释为可以将Y的第j列(因为Y表示的是列的集合)移到第i列,使得a[i][i]变成1,这样就相当于是第i行第i列就变成了1,也就是说对角线多了一个1。
因此我们求这个二分图的最大匹配(目的是为了让每一列只与X中的某一行匹配),这样来就形成了N条边,那我们只需要将所有匹配的边的右边(列) 和 左边(行)所在的列 交换,这样一来对角线上这一行就成了1.
上面也也正好提示了如果最大匹配是N,那就存在解,否则无解。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
bool map[110][110];
int boy[110];
int used[110];
int n;
int x[2000],y[2000];
bool f(int u)
{
for(int i=1;i<=n;++i)
{
if(map[u][i]&&!used[i])
{
used[i]=1;
if(boy[i]==-1 || f(boy[i]) )
{
boy[i]=u; return 1;
}
}
}
return 0;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(map,0,sizeof(map));
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
int c;
scanf("%d",&c);
if(c) map[i][j]=1;
}
}
memset(boy,-1,sizeof(boy));
int ans=0;
for(int i=1;i<=n;++i)
{
memset(used,0,sizeof(used));
if(f(i)) ans++;
}
if(ans<n)
{
printf("-1\n");
continue;
}
else
{
int ans=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
if(boy[j]==i&&i!=j)
{
x[ans]=i; y[ans++]=j;
swap(boy[i],boy[j]);
break;
}
}
}
printf("%d\n",ans);
for(int i=0;i<ans;++i)
{
printf("C %d %d\n",x[i],y[i]);
}
}
}
return 0;
}