坑爹啊!!!!!!!
这题弄了我一天啊!到最后在样例都没过的情况下,怀着无语的心情蛮交了一次,竟然过了!这不是坑爹是什么!
不过分析了一下,这样的情况应该也是算对的!因为增广路可能的情况本身就有许多种,所以样例不过的情况也是允许的吧!
这题的意思其实有点乱,不过梳理一下就比较容易理解,首相想到是网络流的题目比较有困难,然后就是题意了。具体是,以“工厂”作为节点,intput 全为2是与源点连通,制造一个0为源点,2*n+1为汇点。。
剩下的把每个机器(节点)分解成两个点(i,i+n),这两个点之间最大流量即为Performance。。
其他可用的边流量都是无穷大,记得1-n的点只能进,n+1-2*n的点只能出。。。
例如:机器i的完成品可用到j上加工 maxflow[i+n][j]=MAXINT。。。祝大家最大流愉快!
附上代码,其实主要是我一直想使用自己的Dinic模板,不想换,所以坑了我一整天。
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn=150000;
const int maxm=200000;
const int inf=1<<30;
struct edge
{
int from,to,val,next;
int flow;
}map[maxn];
edge lex[500];
int vis[maxn],que[maxn],dist[maxn],len,n;
int vised[maxn];
int pcnt=0;
int T;
void init()
{
len=0;
memset(vis,-1,sizeof(vis));
}
void insert (int from,int to,int val)
{
map[len].from=from;
map[len].to=to;
map[len].val=val;
map[len].flow=val;
map[len].next=vis[from];
vis[from]=len++;
map[len].from=to;
map[len].to=from;
map[len].val=0;
map[len].flow=0;
map[len].next=vis[to];
vis[to]=len++;
}
int Dinic(int n,int s,int t)
{
int ans=0;
while(true)
{
int head,tail,id,i;
head=tail=0;
que[tail++]=s;
memset(dist,-1,sizeof(dist));
dist[s]=0;
while(head<tail)
{
id=vis[que[head++]];
while(id!=-1)
{
if(map[id].val>0&&dist[map[id].to]==-1)
{
dist[map[id].to]=dist[map[id].from]+1;
que[tail++]=map[id].to;
if(map[id].to==t)
{
head=tail;
break;
}
}
id=map[id].next;
}
}
if(dist[t]==-1)
break;
id=s,tail=0;
while(true)
{
if(id==t) //找到一条增广路
{
int flow=inf,fir;
for(i=0;i<tail;i++)
if(map[que[i]].val<flow)
{
fir=i;
flow=map[que[i]].val;
}
for(i=0;i<tail;i++)
map[que[i]].val-=flow,map[que[i]^1].val+=flow;
ans+=flow;
tail=fir;
id=map[que[fir]].from;
}
id=vis[id];
while(id!=-1)
{
if(map[id].val>0&&dist[map[id].from]+1==dist[map[id].to])
break;
id=map[id].next;
}
if(id!=-1)
{
que[tail++]=id;
id=map[id].to;
}
else
{
if(tail==0)
break;
dist[map[que[tail-1]].to]=-1;
id=map[que[--tail]].from;
}
}
}
return ans;
} //以上依然是纯模板
int main()
{
int p,i,j,k;
int num[51][101];
while(scanf("%d%d",&p,&n)!=EOF)
{
int flag,flag1;
init();
memset(num,0,sizeof(num));
T=2*n+1;
for(i=1;i<=n;i++)
for(j=0;j<=2*p;j++)
scanf("%d",&num[i][j]); //建图输入 num[i][0] 都未这个工厂的效率
for(i=1;i<=n;i++)
{
flag=1;
flag1=1;
insert(i,i+n,num[i][0]);
for(j=1;j<=p;j++)
{
if(num[i][j]!=0&&num[i][j]!=2) //判断是否和源点相连
flag=0;
if(num[i][j+p]!=1) //判断是否和汇点相连
flag1=0;
}
if(flag)
insert(0,i,num[i][0]); //运用上面的判断是否建立边
if(flag1)
insert(n+i,2*n+1,num[i][0]);
for(j=1;j<=n;j++)
{
int kkk=1;
for(k=1;k<=p;k++)
if(j!=i)
if(num[i][k+p]!=num[j][k]&&num[j][k]!=2) //判断前一个工厂的结果是否为下一个工厂的前提
{
kkk=0;
break;
}
if(kkk)
{
insert(i+n,j,inf);
}
}
}
memset(vised,0,sizeof(vised));
int ans=Dinic(T+1,0,T);
pcnt=0;
for(i=n+1;i<=2*n+1;i++)
for(j=vis[i];j!=-1;j=map[j].next)
if(map[j].to>0&&map[j].to<=n&&map[j].val<map[j].flow) //这个地方坑了我无限久,找残留网络中的点,不为0或者不为inf值就是需要的边
pcnt++;
printf("%d %d\n",ans,pcnt);
for(i=n+1;i<=2*n+1;i++)
for(j=vis[i];j!=-1;j=map[j].next) //再来一次输出就好
if(map[j].to>0&&map[j].to<=n&&map[j].val<map[j].flow)
cout<<i-n<<" "<<map[j].to<<" "<<map[j].flow-map[j].val<<endl;
}
return 0;
}
依然希望大家自己去考虑考虑,模板什么都坚持使用一种!