hdu(1498和2119)气球,最小点覆盖
2013-08-11 00:51
399 查看
大意:给你一个0/1矩阵,以及一把枪,一枪可以打掉同一行或者同一列上的1,问你最少几次可以把1全部变为0?
思路:我们以x,y轴为顶点建立二分图,如果数字为1的话,那么就连一条边,其实就转换成了最小顶点覆盖的问题,然后用ED算法求二分最大匹配即可.
注意:
1、最大的匹配顶点数应该为n,所以for(int i = 1; i <= n; i++) ED(i);
2、矩阵数据范围是1~100,所以最大的边数应该是100*100才对,否则RE.
#include<stdio.h>
#include<string.h>
int map[1000][1000];
int link[1000],mark[1000];
int m,n;
int find(int k)//////就处理一种一种颜色,所以一个变量,下面要两个。。、
{
int i;
for(i=1;i<=m;i++)
{
if(mark[i]==0&&map[k][i])
{
mark[i]=1;
if(link[i]==0||find(link[i]))
{
link[i]=k;
return 1;
}
}
}
return 0;
}
int main()
{
int i,j,k,sum;
while(scanf("%d",&n),n)
{
scanf("%d",&m);
memset(map,0,sizeof(map));
memset(link,0,sizeof(link));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%d",&k);
if(k==1)
map[i][j]=1;
}
sum=0;
for(i=1;i<=n;i++)
{
memset(mark,0,sizeof(mark));
if(find(i))
sum++;
}
printf("%d\n",sum);
}
return 0;
}
大家可以先做一下hdu 2119,每次只能删除一行或一列的1,求的是最少多少次能把1删除完,以行为一个子集,列为一个子集,如果map[i][j]=1就是i与j建一条边,把1删除完,就是每条边都要被删除,就是最小点覆盖问题,这一题也是每次只能消除一行或一列的相同颜色的气球,要求出删除每一种颜色的气球最少需要多少次,如果大于k的话就不能删除完,要求的就是不能被删除完的。每一种气球就相当于hdu
2119的1,也是求最小点覆盖。。
1498
题意:给你一个n*n的矩阵,在矩阵中分布着s种颜色的气球,给你k次扎破气球的操作,每次操作可以扎破一行,或一列的同一颜色的气球。问在k次操作后有哪几种颜色的气球是不能被完全扎破的。
解题:
利用二分图匹配,寻找每一种颜色对应的最大匹配(行和列分别为A集合,B集合;M[i,j]代表一个搭配),如果大于k则输出“-1”,否则输出颜色的递增序列。
注:在二分图中求最少的点,让每条边都至少和其中的一个点关联,这就是二分图的“最小顶点覆盖”。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int map[101][101];
int color[51],link[101];
int mark[101],p[51];
int n;
int cmp(const void*a,const void *b)
{
return *(int*)a-*(int*)b;
}
int find(int k,int h)
{
int i;
for(i=1;i<=n;i++)
{
if(mark[i]==0&&map[k][i]==h)//相同颜色的才能匹配(重点)
{
mark[i]=1;
if(link[i]==0||find(link[i],h))----find两个量。。
{
link[i]=k;
return 1;
}
}
}
return 0;
}
int main()
{
int i,j,m,k,h,sum;
while(scanf("%d%d",&n,&m),n||m)
{
k=1;
memset(map,0,sizeof(map));
memset(mark,0,sizeof(mark));
memset(color,0,sizeof(color));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
if(mark[map[i][j]]==0)
{
mark[map[i][j]]=1;
color[k]=map[i][j];//颜色的种数
k++;
}
}
h=0;
for(i=1;i<=k;i++)/求每种颜色被删除的最小次数(((每一种操作和上面对一处理的方式一样,这里多种颜色,所以要多次处理))每次都要初始化))
{
memset(link,0,sizeof(link));
sum=0;
for(j=1;j<=n;j++)
{
memset(mark,0,sizeof(mark));
sum+=find(j,color[i]);
}
if(sum>m)
{
p[h]=color[i];/统计不能被删除的颜色
h++;
}
}
qsort(p,h,sizeof(p[0]),cmp);排序
if(h==0)
printf("-1\n");
else
{
for(i=0;i<h-1;i++)
printf("%d ",p[i]);
printf("%d\n",p[h-1]);
}
}
return 0;
}
思路:我们以x,y轴为顶点建立二分图,如果数字为1的话,那么就连一条边,其实就转换成了最小顶点覆盖的问题,然后用ED算法求二分最大匹配即可.
注意:
1、最大的匹配顶点数应该为n,所以for(int i = 1; i <= n; i++) ED(i);
2、矩阵数据范围是1~100,所以最大的边数应该是100*100才对,否则RE.
#include<stdio.h>
#include<string.h>
int map[1000][1000];
int link[1000],mark[1000];
int m,n;
int find(int k)//////就处理一种一种颜色,所以一个变量,下面要两个。。、
{
int i;
for(i=1;i<=m;i++)
{
if(mark[i]==0&&map[k][i])
{
mark[i]=1;
if(link[i]==0||find(link[i]))
{
link[i]=k;
return 1;
}
}
}
return 0;
}
int main()
{
int i,j,k,sum;
while(scanf("%d",&n),n)
{
scanf("%d",&m);
memset(map,0,sizeof(map));
memset(link,0,sizeof(link));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%d",&k);
if(k==1)
map[i][j]=1;
}
sum=0;
for(i=1;i<=n;i++)
{
memset(mark,0,sizeof(mark));
if(find(i))
sum++;
}
printf("%d\n",sum);
}
return 0;
}
大家可以先做一下hdu 2119,每次只能删除一行或一列的1,求的是最少多少次能把1删除完,以行为一个子集,列为一个子集,如果map[i][j]=1就是i与j建一条边,把1删除完,就是每条边都要被删除,就是最小点覆盖问题,这一题也是每次只能消除一行或一列的相同颜色的气球,要求出删除每一种颜色的气球最少需要多少次,如果大于k的话就不能删除完,要求的就是不能被删除完的。每一种气球就相当于hdu
2119的1,也是求最小点覆盖。。
1498
题意:给你一个n*n的矩阵,在矩阵中分布着s种颜色的气球,给你k次扎破气球的操作,每次操作可以扎破一行,或一列的同一颜色的气球。问在k次操作后有哪几种颜色的气球是不能被完全扎破的。
解题:
利用二分图匹配,寻找每一种颜色对应的最大匹配(行和列分别为A集合,B集合;M[i,j]代表一个搭配),如果大于k则输出“-1”,否则输出颜色的递增序列。
注:在二分图中求最少的点,让每条边都至少和其中的一个点关联,这就是二分图的“最小顶点覆盖”。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int map[101][101];
int color[51],link[101];
int mark[101],p[51];
int n;
int cmp(const void*a,const void *b)
{
return *(int*)a-*(int*)b;
}
int find(int k,int h)
{
int i;
for(i=1;i<=n;i++)
{
if(mark[i]==0&&map[k][i]==h)//相同颜色的才能匹配(重点)
{
mark[i]=1;
if(link[i]==0||find(link[i],h))----find两个量。。
{
link[i]=k;
return 1;
}
}
}
return 0;
}
int main()
{
int i,j,m,k,h,sum;
while(scanf("%d%d",&n,&m),n||m)
{
k=1;
memset(map,0,sizeof(map));
memset(mark,0,sizeof(mark));
memset(color,0,sizeof(color));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
if(mark[map[i][j]]==0)
{
mark[map[i][j]]=1;
color[k]=map[i][j];//颜色的种数
k++;
}
}
h=0;
for(i=1;i<=k;i++)/求每种颜色被删除的最小次数(((每一种操作和上面对一处理的方式一样,这里多种颜色,所以要多次处理))每次都要初始化))
{
memset(link,0,sizeof(link));
sum=0;
for(j=1;j<=n;j++)
{
memset(mark,0,sizeof(mark));
sum+=find(j,color[i]);
}
if(sum>m)
{
p[h]=color[i];/统计不能被删除的颜色
h++;
}
}
qsort(p,h,sizeof(p[0]),cmp);排序
if(h==0)
printf("-1\n");
else
{
for(i=0;i<h-1;i++)
printf("%d ",p[i]);
printf("%d\n",p[h-1]);
}
}
return 0;
}
相关文章推荐
- hdu 2119 Matrix (最小覆盖)
- hdu 1498 50 years, 50 colors(二分匹配,最小点覆盖)
- HDU 1498 50 years, 50 colors 最小点覆盖
- HDU 1498 50 years, 50 colors 二分图最小点覆盖(基础题)
- hdu 2119最小点集覆盖
- hdu 1498(二分图最小顶点覆盖)
- HDU 1498 50 years, 50 colors 二分图最小点覆盖
- HDU 1498 50 years, 50 colors (二分图最小顶点覆盖)
- hdu 1498 50 years, 50 colors(最小顶点覆盖)
- HDU 2119 Matrix(二分图最小顶点覆盖)
- HDU 2119 Matrix [二分图匹配之最小覆盖]
- HDU 1498 50 years, 50 colors(最小顶点覆盖)
- 【二分图匹配(最小顶点覆盖)】hdu 1498 50 years,50 colors
- hdu 2119 最小点覆盖
- hdu 2119 Matrix【最小点覆盖-二分匹配】
- hdu1498匈牙利算法/最小点覆盖
- 50 years, 50 colors HDU - 1498(最小点覆盖或者说最小顶点匹配)
- hdu1498—50 years, 50 colors(最小点覆盖)
- HDU 1498 50 years, 50 colors (行列匹配+最小顶点覆盖)
- hdu 1498 50 years, 50 colors(二分图匹配--最小点覆盖)