题目地址:http://poj.org/problem?id=3436
写了起码4hour+....
假设两个超级汇点源点,到000,和111点
因为p最大只有10,所以一个整数就能保存
保存点比较麻烦,一开始想的是map 给每个点一个id,但是两个相同的点,比如说010,不能看成同一个点,因为机器都不同,等下路径都找不了了
所以用in[],out[]保存出来的点和进去的点,当out[u]==in[v]说明u-->v
还要输出路径,也就是协作关系:
1)方法一就是备份初始的图,当流量变少了,说明肯定流过
2)方法二就是根据剩下来的残余网络,如果反向边G[v][u]>0 ,说明u->v流过,这样可以省一个数组空间
然后我一直错的一个点就是,一直写超级源点到000而忽略了存在2的情况如020 ,超级汇点也是如此
#include<iostream>
#include<queue>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100+5;
const int INF=1000000000;
int G[maxn][maxn];
int PriG[maxn][maxn];
int prev[maxn]; //记录前驱节点,记录增广路径
bool vis[maxn];
int read(int k,int& x) //if k>0 in,else out
{
bool s=false,t=false;
if(k>0) s=true;
else t=true;
x=0;int n=1;
for(int i=0;i<fabs(k);i++){
cin>>n;
x=x*10+n;
if(k>0&&n==1) s=false;
if(k<0&&n==0) t=false;
}
if(s) return 0; //is 000 注意其中有2也算
if(t) return 1; //is 111
return -1;
}
bool check(int n1,int n2)
{
int i,j;
for(;;)
{
if(n1==0&&n2==0) break;
i=n1%10,j=n2%10;
if(i+j==1) return false;
n1/=10;
n2/=10;
}
return true;
}
int Augment(int s,int t) //增广
{
queue<int> Q;
bool isFound=false; //标记是否找到了增广路
memset(vis,false,sizeof(vis));
memset(prev,-1,sizeof(prev));
Q.push(s);
vis[s]=true;
while(!Q.empty())
{
int u=Q.front(); Q.pop();
if(u==t) { //找到增广路径了
isFound=true;
break;
}
for(int v=0;v<=t;v++)
if(u!=v&&G[u][v]>0&&!vis[v]){
prev[v]=u;
vis[v]=true;
Q.push(v);
}
}
if(!isFound) return 0; //无路可走
int MinFlow=INF;
int u=t;
while(u!=s){ //计算途中最小流
MinFlow=min(MinFlow,G[prev[u]][u]);
u=prev[u];
}
u=t;
while(u!=s){
G[prev[u]][u]-=MinFlow; //更新途径路的流量
G[u][prev[u]]+=MinFlow; //加上反向边
u=prev[u];
}
return MinFlow;
}
void printPath(int m)
{
vector<int> s,e,w;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(i!=j&&PriG[i+m][j]>G[i+m][j]) //in->out 反向边
{
s.push_back(i);
e.push_back(j);
w.push_back(PriG[i+m][j]-G[i+m][j]);
}
cout<<s.size()<<endl;
for(int i=0;i<s.size();i++)
printf("%d %d %d\n",s[i],e[i],w[i]);
}
int in[maxn];
int out[maxn];
int main()
{
int n,m;
while(cin>>n>>m)
{
int u,v,w;
int s=0,t=2*m+1;
for(int i=1;i<=m;i++){
cin>>w;
G[i][i+m]+=w; //1~m是in,m+1~2*m是out ,源点是0,汇点是2*m+1
if(read(n,in[i])==0) G[s][i]+=INF;
if(read(-n,out[i])==1) G[i+m][t]+=INF;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(check(out[j],in[i])) G[j+m][i]+=INF;
memcpy(PriG,G,sizeof(G));
int MaxFlow=0;
int aug;
while(aug=Augment(s,t))
MaxFlow+=aug; //加上每次增广的流
cout<<MaxFlow<<' ';
printPath(m);
}
return 0;
}