最近难得1A的题目
虽然也是道蛮水的网络流,大概这个题的难度在于读题吧。。。我看了一大堆博文才弄清楚这个题的意思
题目意思大概是这样的,给你n个机器,每个机器有一个使用次数,然后有一个进参数和一个出参数,出参数与进参数匹配就可以连边,然后要使最多的全零状态变为1状态
Sample input 1
3 4
15 0 0 0 0 1 0
10 0 0 0 0 1 1
30 0 1 2 1 1 1
3 0 2 1 1 1 1
用sample来解释,现在的总状态参数是3(p=3);
一开始的状态是(0,0,0);
然后我可以通过第一个machine使状态从(0,0,0)变为(0,1,0),然后再通过第2个machine使状态从(0,1,0)变为(1,1,1,);这样最多可以变化15次因为有15个machine1;
这样的话算法就很明显了,建一个源点一个汇点,源点向所有入点为(0,0,0,0,0,,,,0)(ps:也可以有2),连一条无穷大的边,然后所有出点为(1,1,1,1,1.1...1)的向出点连无穷大的
边。然后不同机器如果出点入点相匹配的话从出点向入点连边。然后每一个机器的入点向出点连一条容量大小的边,这样做最大流就可以了。
因为是special judge所以输出也是比较随意。。。判断一下不同机器之间连的边与初始值的差。
说些题外话,最近虽然是进了acm队但是还是明显觉得实力差的非常多,接下来也打算按照翁队的教诲,认真把每一种类型的题目都刷通。也希望有志于打acm的coder于蒟蒻相互交流拉。。。。留个邮箱prospace@126.com~
最后把这个题代码粘了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int p,q,n,st,ed,tot=0,link[2010],h[2010],sum[2010];
int s[61][3][21];
struct rec
{
int num,dis,w,next;
}e[500100];
void insert(int x,int y,int w){
tot++;e[tot].num=y;e[tot].w=w;e[tot].next=link[x];e[tot].dis=tot+1;link[x]=tot;
tot++;e[tot].num=x;e[tot].w=0;e[tot].next=link[y];e[tot].dis=tot-1;link[y]=tot;
}
void Input()
{//读入,建自边;建源点,汇点边 ;
int tmp_tot;
scanf("%d%d",&p,&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&q);
insert(i,n+i,q);
tmp_tot=0;
for (int j=1;j<=p;j++)
{
scanf("%d",&s[i][1][j]);
if (s[i][1][j]==1) tmp_tot++;
}
if (tmp_tot==0) insert(2*n+1,i,2000000);
tmp_tot=0;
for (int j=1;j<=p;j++)
{
scanf("%d",&s[i][2][j]);
if (s[i][2][j]==0) tmp_tot++;
}
if (tmp_tot==0) insert(i+n,2*n+2,2000000);
}
}
void clear()//初始化
{
memset(s,0,sizeof(s));
memset(e,0,sizeof(e));
memset(link,0,sizeof(link));
memset(h,0,sizeof(h));
memset(sum,0,sizeof(sum));
tot=0;
}
void make_net()//连相互之间的边,出入点互相连
{
bool flag;
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
{
flag=true;
for (int k=1;k<=p;k++)//s[i]的出到s[j]的入;
if ((s[i][2][k]==0&&s[j][1][k]==1)||(s[i][2][k]==1&&s[j][1][k]==0))
{
flag=false;
break;
}
if (flag==true) insert(i+n,j,2000000);
flag=true;
for (int k=1;k<=p;k++)//s[j]的出到s[i]的入;
if ((s[i][1][k]==0&&s[j][2][k]==1)||(s[i][1][k]==1&&s[j][2][k]==0))
{
flag=false;
break;
}
if (flag==true) insert(j+n,i,2000000);
flag=true;
}
}
int dfs(int x,int total)
{
if (x==ed) return total;
int minh=2*n+1,leave=total,w;
for (int p=link[x];p;p=e[p].next)
{
//printf("%d %d %d %d\n",x,total,p,e[p].num);
if (e[p].w>0)
{
if (h[x]==h[e[p].num]+1)
{
w=dfs(e[p].num,min(e[p].w,leave));
e[p].w-=w;
e[e[p].dis].w+=w;
leave-=w;
if (h[st]==ed) return total-leave;
}
minh=min(h[e[p].num],minh);
}
}
if (leave==total)
{
sum[h[x]]--;
if (sum[h[x]]==0)
h[st]=ed;
h[x]=minh+1;
sum[h[x]]++;
}
return total-leave;
}
void net_work()
{
int ans=0;
while (h[st]<2*n+2)
{
ans+=dfs(st,2000000);
/*for (int ii=1;ii<=10;ii++)
{
printf("%d ",h[ii]);
}
printf("\n");
for (int ii=1;ii<=10;ii++)
{
printf("%d ",s[ii]);
}
printf("\n");*/
}
printf("%d",ans);
}
int main()
{
clear();
Input();
make_net();
st=2*n+1;
ed=st+1;
sum[0]=2*n+2;
net_work();
int tmp_ans=0;
for (int i=1;i<=n;i++)
for (int p=link[i+n];p;p=e[p].next)
if (e[p].num!=i&&e[p].num!=2*n+2&&e[p].num!=2*n+1&&e[p].w!=2000000)
tmp_ans++;
printf(" %d\n",tmp_ans);
for (int i=1;i<=n;i++)
for (int p=link[i+n];p;p=e[p].next)
if (e[p].num!=i&&e[p].num!=st&&e[p].num!=ed&&e[p].w!=2000000)
printf("%d %d %d\n",i,e[p].num,2000000-e[p].w);
return 0;
}