您的位置:首页 > 其它

最大流,Floyd(UNIX插头 uva 753)

2016-07-14 14:12 260 查看
给n个插座,m个设备和k种转换器(n,m,k<=100),每种转换器有无限多。已知每个插座类型,每个设备的插头类型,以及每种转换器的插座类型和插头类型。插头和插座类型用不超过24各字母表示,插头只能插到类型相同的插座中。一个设备的插头可以直接插入插座中也可以经过一个或多个转换器后再插入插座中。

一开始跟着紫书上的提示做的。每个设备连到源点,容量为1。每个插座连到汇点,容量为1。

转换器有无限多而且一个设备的插头可以经过任意多的转换器后再插入插座中。因此我们不需要知道转换的过程,只需要知道某个设备的插头类型最后是否能转换成某个插座的类型即可。

因此建立一个转换器的有向图,类型为点,转换器为有向边。然后通过Floyd算法得到此图的闭包传递,即某个插头最终能否转换成某个插座。

若能,则从设备的插头连一条弧到插座,容量为1。然后从源点到汇点跑一遍最大流即可。

事实上我觉得这个方法挺麻烦,毕竟Floyd算法的时间复杂度为O(n^3),若不是因为此题数据量小,估计就得超时了。因此我改进了一下算法,将转换器作为一个节点纳入到网络流模型中。

其实我是受到了另外一题的启发 http://blog.csdn.net/xl2015190026/article/details/51902823 这是我写的另一题的题解。

在上面这篇博客中,我们利用拆点法来使士兵只能移动一次而不是移动无限次。然而在此题,我们则希望转换器能够无限的转换下去,而不是只转换一次。因此可以考虑把点合并。本来转换器是两个点的,我们把它合并成一个点,然后纳入到网络流模型中。

每个设备连到源点和匹配的转换器插座,容量为1。每个插座连到汇点和比配的转换器插头,容量为1。每个转换器的插头连到其他匹配的转换器的插座上。从源点到汇点跑一遍网络流即可。

注意:别忘了把插头直接连到匹配的插座上。还有Floyd算法要先预处理一下。每个例子间输出空行。

PS:事实上还可以优化,我们没必要把每个插头和插座都变成一个点,只需要把每种类型变成一个点即可,然后弧的容量改为这种类型的个数即可。不过反正数据量那么小,怎样都行。

附上三份渣代码,没太大区别的。

1、最开始写的,Floyd,有些麻烦。

2、优化后的Floyd。

3、合点法。

#include<stdio.h>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<string.h>
#include<string>
#define maxn 500
#define INF 0X3F3F3F3F
using namespace std;

int n,m,k;
map<int,string>STR;
bool MAP[210][210];

struct Edge
{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};

struct EdmondsKarp
{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
int a[maxn];
int p[maxn];

void init(int n)
{
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
edges.clear();
}

void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

int Maxflow(int s,int t)
{
int flow=0;
for(;;)
{
memset(a,0,sizeof(a));
queue<int>Q;
Q.push(s);
a[s]=INF;
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(unsigned int i=0;i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(!a[e.to]&&e.cap>e.flow)
{
p[e.to]=G[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u=t;u!=s;u=edges[p[u]].from)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
flow+=a[t];
}
return flow;
}
void debug()
{
for(int i=0;i<m;i+=2)
printf("              %d %d %d %d\n",edges[i].from,edges[i].to,edges[i].flow,edges[i].cap);
}
};

EdmondsKarp EK;

void Floyd()
{
int cnt=0;
memset(MAP,0,sizeof(MAP));
map<string,int>I;
map<int,string>S;
for(int i=1;i<=k;i++)
{
if(!I[STR[i+100]]) {I[STR[i+100]]=++cnt;S[cnt]=STR[i+100];}
if(!I[STR[i+200]]) {I[STR[i+200]]=++cnt;S[cnt]=STR[i+200];}
}
for(int i=1;i<=k;i++) {MAP[I[STR[i+100]]][I[STR[i+200]]]=true;EK.AddEdge(i+m,i+m+k,INF);}
for(int u=1;u<=cnt;u++)
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
MAP[i][j]=MAP[i][j]||(MAP[i][u]&&MAP[u][j]);
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
if(i!=j&&MAP[I[STR[i+100]]][I[STR[j+200]]]) EK.AddEdge(i+m,j+m+k,INF);
}

int main()
{
int t;
string s1,s2;
scanf("%d",&t);
while(t--)
{
STR.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s1;
STR[i+300]=s1;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
cin>>s1>>s1;
STR[i]=s1;
}
scanf("%d",&k);
EK.init(n+m+k+k+2);
for(int i=1;i<=k;i++)
{
cin>>s1>>s2;
STR[i+100]=s1;
STR[i+200]=s2;
}
Floyd();
for(int i=1;i<=m;i++)
{
EK.AddEdge(0,i,1);
for(int j=1;j<=k;j++)
if(STR[i]==STR[j+100]) EK.AddEdge(i,j+m,1);
for(int j=1;j<=n;j++)
if(STR[i]==STR[j+300]) EK.AddEdge(i,j+m+k+k,1);
}
for(int i=1;i<=n;i++)
{
EK.AddEdge(i+m+k+k,EK.n-1,1);
for(int j=1;j<=k;j++)
if(STR[j+200]==STR[i+300]) EK.AddEdge(j+m+k,i+m+k+k,1);
}
//EK.debug();
printf("%d\n",m-EK.Maxflow(0,EK.n-1));
if(t) puts("");
}
return 0;
}

#include<stdio.h>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<string.h>
#include<string>
#define maxn 500
#define INF 0X3F3F3F3F
using namespace std;

int n,m,k;
map<int,string>STR;
bool MAP[210][210];

struct Edge
{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};

struct EdmondsKarp
{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
int a[maxn];
int p[maxn];

void init(int n)
{
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
edges.clear();
}

void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

int Maxflow(int s,int t)
{
int flow=0;
for(;;)
{
memset(a,0,sizeof(a));
queue<int>Q;
Q.push(s);
a[s]=INF;
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(unsigned int i=0;i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(!a[e.to]&&e.cap>e.flow)
{
p[e.to]=G[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u=t;u!=s;u=edges[p[u]].from)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
flow+=a[t];
}
return flow;
}
void debug()
{
for(int i=0;i<m;i+=2)
printf("              %d %d %d %d\n",edges[i].from,edges[i].to,edges[i].flow,edges[i].cap);
}
};

EdmondsKarp EK;

void Floyd()
{
int cnt=0;
memset(MAP,0,sizeof(MAP));
map<string,int>I;
map<int,string>S;
for(int i=1;i<=k;i++)
{
if(!I[STR[i+100]]) {I[STR[i+100]]=++cnt;S[cnt]=STR[i+100];}
if(!I[STR[i+200]]) {I[STR[i+200]]=++cnt;S[cnt]=STR[i+200];}
}
for(int i=1;i<=k;i++) MAP[I[STR[i+100]]][I[STR[i+200]]]=true;
for(int u=1;u<=cnt;u++)
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
MAP[i][j]=MAP[i][j]||(MAP[i][u]&&MAP[u][j]);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(MAP[I[STR[i]]][I[STR[j+300]]]) EK.AddEdge(i,j+m,INF);
}

int main()
{
int t;
string s1,s2;
scanf("%d",&t);
while(t--)
{
STR.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s1;
STR[i+300]=s1;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
cin>>s1>>s1;
STR[i]=s1;
}
scanf("%d",&k);
EK.init(n+m+2);
for(int i=1;i<=k;i++)
{
cin>>s1>>s2;
STR[i+100]=s1;
STR[i+200]=s2;
}
Floyd();
for(int i=1;i<=m;i++)
{
EK.AddEdge(0,i,1);
for(int j=1;j<=n;j++)
if(STR[i]==STR[j+300]) EK.AddEdge(i,j+m,1);
}
for(int i=1;i<=n;i++)
EK.AddEdge(i+m,EK.n-1,1);
//EK.debug();
printf("%d\n",m-EK.Maxflow(0,EK.n-1));
if(t) puts("");
}
return 0;
}

#include<stdio.h>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<string.h>
#include<string>
#define maxn 500
#define INF 0X3F3F3F3F
using namespace std;

int n,m,k;
map<int,string>STR;

struct Edge
{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};

struct EdmondsKarp
{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
int a[maxn];
int p[maxn];

void init(int n)
{
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
edges.clear();
}

void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

int Maxflow(int s,int t)
{
int flow=0;
for(;;)
{
memset(a,0,sizeof(a));
queue<int>Q;
Q.push(s);
a[s]=INF;
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(unsigned int i=0;i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(!a[e.to]&&e.cap>e.flow)
{
p[e.to]=G[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u=t;u!=s;u=edges[p[u]].from)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
flow+=a[t];
}
return flow;
}
void debug()
{
for(int i=0;i<m;i+=2)
printf("              %d %d %d %d\n",edges[i].from,edges[i].to,edges[i].flow,edges[i].cap);
}
};

int main()
{
int t;
string s1,s2;
scanf("%d",&t);
while(t--)
{
STR.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s1;
STR[i+300]=s1;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
cin>>s1>>s1;
STR[i]=s1;
}
scanf("%d",&k);
EdmondsKarp EK;
EK.init(n+m+k+2);
for(int i=1;i<=k;i++)
{
cin>>s1>>s2;
STR[i+100]=s1;
STR[i+200]=s2;
}
for(int i=1;i<=m;i++)
{
EK.AddEdge(0,i,1);
for(int j=1;j<=k;j++)
if(STR[i]==STR[j+100]) EK.AddEdge(i,j+m,1);
for(int j=1;j<=n;j++)
if(STR[i]==STR[j+300]) EK.AddEdge(i,j+m+k,1);
}
for(int i=1;i<=n;i++)
{
EK.AddEdge(i+m+k,EK.n-1,1);
for(int j=1;j<=k;j++)
if(STR[j+200]==STR[i+300]) EK.AddEdge(j+m,i+m+k,1);
}
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
if(i!=j&&STR[i+200]==STR[j+100]) EK.AddEdge(i+m,j+m,INF);
//EK.debug();
printf("%d\n",m-EK.Maxflow(0,EK.n-1));
if(t) puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最大流 Floyd 紫书 UVA