Problem 1001(HDU 1083 Courses)
题目大意:
给你p门课程和n个学生,一个学生可以选0门,1门,或者多门课程,现在要求一个由p个学生组成的集合,满足下列2个条件:
1.每个学生选择一个不同的课程
2.每个课程都有不同的代表
如果满足,就输出YES
二分图的最大匹配;
学生和课程分别为定点集合vx vy
把学生和他喜欢的的课程连一条边;
#include<iostream>
using namespace std;
const int N=500;
int vx,vy;
int graph[N][N];
int link[N];
bool visit[N];
bool dfs(int u)
{
for(int i=1;i<=vy;i++)
{
if(graph[u][i] && !visit[i])
{
visit[i]=true;
if(link[i]==-1 || dfs(link[i]))
{
link[i]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int max_match=0;
for(int i=1;i<=vx;i++)
{
memset(visit,false,sizeof(visit));
if(dfs(i))
max_match++;
}
return max_match;
}
int main()
{
int cases;
scanf("%d",&cases);
while(cases--)
{
memset(graph,0,sizeof(graph));
memset(link,-1,sizeof(link));
int p,n;
scanf("%d%d",&p,&n);
vx=p;
vy=n;
int stu_num;
int tmp;
/*Input & Structure Graph*/
for(int i=1;i<=p;i++)
{
scanf("%d",&stu_num);
for(int j=1;j<=stu_num;j++)
{
scanf("%d",&tmp);
graph[i][tmp]=1;//
}
}
printf("%s\n", hungary() == p ? "YES" : "NO");
}
return 0;
}
Problem 1002(hdu 1002 Machine Schedule)
题目大意:
有k个任务,A和B两种机器,两种机器分别有vx和vy种模式;
每个任务可以分别在两种机器的某一种模式上运行,问及其转换模式最少几次可以完成k个任务;
思路:
二分的最小顶点覆盖问题;
最小顶点覆盖=最大匹配数
#include<iostream>
using namespace std;
const int N=500;
int vx,vy;
int graph[N][N];
int link[N];
bool visit[N];
bool dfs(int u)
{
for(int i=1;i<=vy;i++)
{
if(graph[u][i] && !visit[i])
{
visit[i]=true;
if(link[i]==-1 || dfs(link[i]))
{
link[i]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int max_match=0;
for(int i=1;i<=vx;i++)
{
memset(visit,false,sizeof(visit));
if(dfs(i))
max_match++;
}
return max_match;
}
int main(int k)
{
while(~scanf("%d",&vx),vx)
{
memset(graph,0,sizeof(graph));
memset(link,-1,sizeof(link));
scanf("%d%d",&vy,&k);
/*Input & Structure Graph*/
for(int i=1;i<=k;i++)
{
int a,b,t;
scanf("%d%d%d",&t,&a,&b);
graph[a][b]=1;
}
printf("%d\n",hungary());
}
return 0;
}
problem 1003(HDU 1281 棋盘游戏)
中文题 意思就不用说了;
思路:
首先求出二分图最大匹配,
再依次枚举点,去掉该店如果最大匹配数减少了,就是重要点;
#include<iostream>
using namespace std;
const int N=500;
int vx,vy;
int graph[N][N];
int link[N];
bool visit[N];
bool dfs(int u)
{
for(int i=1;i<=vy;i++)
{
if(graph[u][i] && !visit[i])
{
visit[i]=true;
if(link[i]==-1 || dfs(link[i]))
{
link[i]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int max_match=0;
memset(link,-1,sizeof(link));
for(int i=1;i<=vx;i++)
{
memset(visit,false,sizeof(visit));
if(dfs(i))
max_match++;
}
return max_match;
}
int main(int i)
{
int numcase=1;
while(~scanf("%d%d",&vx,&vy))
{
int k;
int a[10500],b[10500];
memset(graph,0,sizeof(graph));
scanf("%d",&k);
for(i=0;i<k;i++)
{
scanf("%d%d",&a[i],&b[i]);
graph[a[i]][b[i]]=1;
}
int maxmatch=hungary();
int temp;
int c=0;
for(i=0;i<k;i++)
{
graph[a[i]][b[i]]=0;
temp=hungary();
if(temp<maxmatch)
c++;
graph[a[i]][b[i]]=1;
}
printf("Board %d have %d important blanks for %d chessmen.\n",numcase++,c,maxmatch);
}
return 0;
}
Problem 1004(HDU Uncle Tom's Inherited Land*)
题目大意:
有个n*m的土地,给出土地中k个1*1的pond的坐标(题目描述中的图b);
先要要出售这块土地,但是规定的允许出售的土地为1*2或者2*1的方块并且不能使pond(题目描述中的图c);
问能出售的方块土地最多有多少快;
思路:
这题建图会比较困难,不过仔细想应该可以想的出来;
代码有用到vector,不懂的去看看相关资料;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define N 10010
vector <int> graph[N];
int n,m,k;
bool used[N];
bool visited[110][110];
int link[N];
bool dfs(int u)
{
for(int i=0;i<graph[u].size();i++)
{
int v=graph[u][i];
if(!used[v])
{
used[v]=true;
if(link[v]==-1 ||dfs(link[v]))
{
link[v]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int max_match=0;
memset(link,-1,sizeof(link));
for(int i=1;i<=n*m;i++)
{
memset(used,false,sizeof(used));
if(dfs(i))
max_match++;
}
return max_match;
}
int main(int i,int j)
{
int u,v;
while(scanf("%d%d",&n,&m),n&&m)
{
/*Initial*/
for(int i=1; i<=n*m; i++)
graph[i].clear();
memset(visited,false,sizeof(visited));
scanf("%d",&k);
for(i=1; i<=k; i++)
{
scanf("%d%d",&u,&v);
visited[u][v]=true;//标记ponds
}
/*Structure Graph*/
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(visited[i][j])//如果是ponds 跳过
continue;
if(i+1<=n && !visited[i+1][j])
{
graph[(i-1)*m+j].push_back( i*m+j );
graph[i*m+j].push_back( (i-1)*m+j );
}
if(j+1<=m && !visited[i][j+1])
{
graph[(i-1)*m+j].push_back( (i-1)*m+j+1 );
graph[(i-1)*m+j+1].push_back( (i-1)*m+j );
}
}
}
int max_num=hungary();
printf("%d\n",max_num/2);
int x1,x2,y1,y2;
for(i=1;i<=n*m;i++)
{
if(link[i]!=-1 && link[link[i]]!=-1 )
{
if(!(y1=i%m))
y1=m;
x1=(i-y1)/m+1;
y2=link[i]%m;
if(!(y2=link[i]%m))
y2=m;
x2=(link[i]-y2)/m+1;
link[i]=link[link[i]]=-1;
printf("(%d,%d)--(%d,%d)\n",x1,y1,x2,y2);
}
}
puts("");
}
return 0;
}
problem 1005(HDU 1068 Girls and Boys)
这里求的最大点独立集,但是要注意的一点是,给出的是同学之间的亲密关系,并没有指出哪些是男哪些是女,所以求出的最大匹配数
要除以2才是真正的匹配数
#include<iostream>
using namespace std;
const int N=501;
int graph[N][N];
int match[N];
bool visit[N];
int vx;
int vy;
bool dfs(int x)
{
for(int y=0;y<vy;y++)
{
if(graph[x][y] && !visit[y])
{
visit[y]=true;
if(match[y]==-1 || dfs(match[y]) )
{
match[y]=x;
return true;
}
}
}
return false;
}
int hungary()
{
int max_match=0;
memset(match,-1,sizeof(match));
for(int x=0;x<vx;x++)
{
memset(visit,false,sizeof(visit));
if(dfs(x))
max_match++;
}
return max_match;
}
int main()
{
int a,b,t;
while(~scanf("%d",&vx))
{
memset(graph,0,sizeof(graph));
vy=vx;
int a,b,t;
for(int i=0;i<vx;i++)
{
scanf("%d: (%d)",&a,&b);
while(b--)
{
scanf("%d",&t);
graph[a][t]=1;
}
}
printf("%d\n",vx-hungary()/2);
}
return 0;
}
problem 1008(hdu 1533 Going Home)
题目大意:
给定一个N*M的地图,地图上有一定数量的m(代表人)和H(代表房子),两者数量相等;
要求求出把所有m移动到H的位置上总距离最小为多少;
思路:
用最优二分匹配或者最小费用最大流都能做,觉得用最优二分匹配会简单一些;
建图把m和H分别作为二分图的两个顶点集合vx和vy,求出两两之间的距离,用km算法求出最优匹配;
要注意的是,要求距离的最短,而km求的是最大匹配值,所以建图的时候距离要取反;
#include<iostream>
#include<cmath>
using namespace std;
const int MAX=105;
const int inf=1<<30;
int n,lack;
int map[MAX][MAX];
char maps[MAX][MAX];
int dx[MAX],dy[MAX];
int link[MAX];
bool visx[MAX],visy[MAX];
bool DFS(int v)
{
visx[v]=true;
for(int i=0;i<n;i++)
{
if(visy[i])
continue;
int t=dx[v]+dy[i]-map[v][i];
if(!t)
{
visy[i]=true;
if(link[i]==-1||DFS(link[i]))
{
link[i]=v;
return true;
}
}
else
if(t<lack)
lack=t;
}
return false;
}
void KM()
{
int i,j;
memset(dx,0,sizeof(dx));
memset(dy,0,sizeof(dy));
memset(link,-1,sizeof(link));
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
if(map[i][j]>dx[i])
dx[i]=map[i][j];
}
for(i=0;i<n;i++)
{
while(true)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
lack=0x7fffffff;
if(DFS(i))
break;
for(j=0;j<n;j++)
{
if(visx[j])
dx[j]-=lack;
if(visy[j])
dy[j]+=lack;
}
}
}
}
int main(int i,int j,int k,int l)
{
int row,col,ans,numi,numj;
while(scanf("%d%d",&row,&col)&&(row+col))
{
/*Initial*/
n=ans=numi=numj=0;
memset(link,-1,sizeof(link));
memset(map,0,sizeof(map));
/*Input*/
for(i=0;i<row;i++)
{
scanf("%*c");
for(j=0;j<col;j++)
{
scanf("%c",&maps[i][j]);
if(maps[i][j]=='m')
n++;
}
}
/*Structure Graph*/
/*±ßȨֵ±äΪ¸ºÈ¨£¬Çó³ö×î´óÆ¥ÅäÖµ¼´Îª×îС¾àÀë×ܺÍ*/
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
if(maps[i][j]=='m')
{
for(k=0;k<row;k++)
{
for(l=0;l<col;l++)
{
if(maps[k][l]=='H')
map[numi][numj++]=-(abs(k-i)+abs(l-j)); //±ßΪ¸ºÈ¨Öµ
}
}
numi++;
numj=0;
}
}
}
KM();
int ans=0;
for(i=0;i<n;i++)
{
if(link[i]!=-1)
ans+=map[link[i]][i];
}
printf("%d\n",-ans);
}
return 0;
}