由于容量限制在点上,不是在边上,所以把一个点拆成两个点,一个是“入口”一个是“出口”,之间用点的容量建一条边...(这让我想到了关于空间维度的问题...= =||)
总结一下初级图论知识:
单源最短路 bell-fordman(用队列优化一下就是spfa,shortest path faster algorithm) 是可以用来找环的,一般是找负环,修改一下能找正环,时间分析:没加优化O(VE),加了优化O(KE)。
单源最短路 dijkstra,只能是正权边,采用贪心策略,加了一些限制的最短路或某些变形的最短路,最好还是用dijkstra,比如poj 1062 有个等级限制,就是一条路的中的边的等级差不能超过某个值, 还有poj2253求的是变形的最短路,要求每条路中的最大权值最小,除了这些变形最短路外,dijkstra还能求k短路,根据k值大小有两种方法,一种是保存多个值跑一次最短路,另一种是短边法...(k短路没做过题,不知道理解的对不对), 时间分析 不用堆优化O(n^2)
多源最短路径 Floyd,Floyd也能判断环(判断g[i][i]是否改变),Floyd还能求最小环的大小,时间分析o(n^3)
最小生成树:prim,kruskal,都是贪心策略,类似dijkstra
拓扑排序
二分图基数最大匹配(匈牙利算法)O(nm)
最大流 SAP O(v^2 E)
下面是POJ3436代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<fstream>
using namespace std;
#define maxv 105
#define INF 0xfffffff
//ofstream fout("result.txt");
int n,pn,P,N;
int F[maxv][maxv];
int G[maxv][maxv];
int d[maxv];
int cnt[maxv];
int cur[maxv];
int p[maxv];
int exist(int u)
{
int i;
for(i=cur[u];i<=n;++i)
{
if(G[u][i]!=0&&d[u]==d[i]+1)
{
cur[u]=i;
// fout<<"exist"<<endl;
return i;
}
}
// fout<<"not exist"<<endl;
return -1;
}
void aug(int &f)
{
int af=INF,i;
for(i=0;i<pn-1;++i)
af=min(af,G[p[i]][p[i+1]]);
for(i=0;i<pn-1;++i)
{
G[p[i]][p[i+1]]-=af;
G[p[i+1]][p[i]]+=af;
F[p[i]][p[i+1]]+=af;
F[p[i+1]][p[i]]=-F[p[i]][p[i+1]];
}
pn=0;
f+=af;
// fout<<"aug"<<endl;
return ;
}
int renew(int u)
{
cur[u]=1;
int i,md=INF;
bool flag=false;
for(i=1;i<=n;++i)
{
if(G[u][i]!=0)
md=min(md,d[i]),flag=true;
}
if(flag)
{
cnt[d[u]]--;
if(cnt[d[u]]==0)
{
// fout<<"renew break"<<endl;
return -1;
}
cnt[md+1]++;
d[u]=md+1;
// fout<<"renew"<<endl;
return 1;
}
else
{
// fout<<"renew fail"<<endl;
return 0;
}
}
int SAP(int s,int t)
{
pn=0;
int f=0,i,j,flag;
memset(d,0,sizeof(d));
memset(cnt,0,sizeof(cnt));
memset(F,0,sizeof(F));
cnt[0]=n;
for(i=1;i<=n;++i)
cur[i]=1;
i=s;
// fout<<"SAP pre end"<<endl;
while(d[s]<n)
{
if((j=exist(i))!=-1)
{
p[pn++]=i;
i=j;
if(i==t)
{
p[pn++]=t;
aug(f);
i=s;
}
}
else
{
flag=renew(i);
if(flag==-1)
return f;
else if(flag==0)
d[i]=n;
if(i!=s)
i=p[--pn];
}
}
// fout<<"SAP end"<<endl;
return f;
}
bool match(char* a,char *b)
{
int i;
for(i=0;i<P;++i)
{
if(b[i]=='2')
continue;
else if(a[i]!=b[i])
return false;
}
return true;
}
int main()
{
// ifstream fin("data.txt");
int i,j,fm,to,cost,s,t,ans,cnt;
char sm[]="0000000000";
char em[]="1111111111";
char in[55][15],out[55][15];
// while(fin>>P>>N)
while(cin>>P>>N)
{
n=2*N+2;
memset(G,0,sizeof(G));
for(i=1;i<=N;++i)
{
// fin>>cost;
cin>>cost;
for(j=0;j<P;++j)
// fin>>in[i][j];
cin>>in[i][j];
for(j=0;j<P;++j)
// fin>>out[i][j];
cin>>out[i][j];
if(match(sm,in[i]))
G[2*N+1][i]=INF;
if(match(out[i],em))
G[i+N][2*N+2]=INF;
G[i][i+N]=cost;
}
// fout<<"input compelete"<<endl;
for(i=1;i<=N;++i)
{
for(j=i+1;j<=N;++j)
{
if(match(out[i],in[j]))
{
G[i+N][j]=INF;
}
if(match(out[j],in[i]))
{
G[j+N][i]=INF;
}
}
}
/*for(i=1;i<=N;++i)
{
for(j=i+1;j<=N;++j)
{
if(G[i+N][j]!=0)
cout<<i<<" "<<j<<endl;
if(G[j+N][i]!=0)
cout<<j<<" "<<i<<endl;
}
}*/
// fout<<"map constructed"<<endl;
ans=SAP(2*N+1,2*N+2);
// cout<<"SAP end"<<endl;
cnt=0;
for(i=1;i<=N;++i)
{
for(j=i+1;j<=N;++j)
{
if(F[i+N][j]>0)
cnt++;
if(F[j+N][i]>0)
cnt++;
}
}
cout<<ans<<" "<<cnt<<endl;
for(i=1;i<=N;++i)
{
for(j=i+1;j<=N;++j)
{
if(F[i+N][j]>0)
{
cout<<i<<" "<<j<<" "<<F[i+N][j]<<endl;
}
if(F[j+N][i]>0)
{
cout<<j<<" "<<i<<" "<<F[j+N][i]<<endl;
}
}
}
}
// system("pause");
return 0;
}
图论算法精要
454

被折叠的 条评论
为什么被折叠?



