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

2021-07-14 22:27:50 字數 4032 閱讀 4215

給n個插座,m個裝置和k種轉換器(n,m,k<=100),每種轉換器有無限多。已知每個插座型別,每個裝置的插頭型別,以及每種轉換器的插座型別和插頭型別。插頭和插座型別用不超過24各字母表示,插頭只能插到型別相同的插座中。乙個裝置的插頭可以直接插入插座中也可以經過乙個或多個轉換器後再插入插座中。

一開始跟著紫書上的提示做的。每個裝置連到源點,容量為1。每個插座連到匯點,容量為1。

轉換器有無限多而且乙個裝置的插頭可以經過任意多的轉換器後再插入插座中。因此我們不需要知道轉換的過程,只需要知道某個裝置的插頭型別最後是否能轉換成某個插座的型別即可。

因此建立乙個轉換器的有向圖,型別為點,轉換器為有向邊。然後通過floyd演算法得到此圖的閉包傳遞,即某個插頭最終能否轉換成某個插座。

若能,則從裝置的插頭連一條弧到插座,容量為1。然後從源點到匯點跑一遍最大流即可。

事實上我覺得這個方法挺麻煩,畢竟floyd演算法的時間複雜度為o(n^3),若不是因為此題資料量小,估計就得超時了。因此我改進了一下演算法,將轉換器作為乙個節點納入到網路流模型中。

其實我是受到了另外一題的啟發 這是我寫的另一題的題解。

在上面這篇部落格中,我們利用拆點法來使士兵只能移動一次而不是移動無限次。然而在此題,我們則希望轉換器能夠無限的轉換下去,而不是只轉換一次。因此可以考慮把點合併。本來轉換器是兩個點的,我們把它合併成乙個點,然後納入到網路流模型中。

每個裝置連到源點和匹配的轉換器插座,容量為1。每個插座連到匯點和比配的轉換器插頭,容量為1。每個轉換器的插頭連到其他匹配的轉換器的插座上。從源點到匯點跑一遍網路流即可。

注意:別忘了把插頭直接連到匹配的插座上。還有floyd演算法要先預處理一下。每個例子間輸出空行。

ps:事實上還可以優化,我們沒必要把每個插頭和插座都變成乙個點,只需要把每種型別變成乙個點即可,然後弧的容量改為這種型別的個數即可。不過反正資料量那麼小,怎樣都行。

附上三份渣**,沒太大區別的。

1、最開始寫的,floyd,有些麻煩。

2、優化後的floyd。

3、合點法。

#include#include#include#include#include#include#include#define maxn 500

#define inf 0x3f3f3f3f

using namespace std;

int n,m,k;

mapstr;

bool map[210][210];

struct edge

};struct edmondskarp

}if(a[t]) break;

}if(!a[t]) break;

for(int u=t;u!=s;u=edges[p[u]].from)

flow+=a[t];

}return flow;

}void debug()

if(!i[str[i+200]])

}for(int i=1;i<=k;i++)

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()

scanf("%d",&m);

for(int i=1;i<=m;i++)

scanf("%d",&k);

ek.init(n+m+k+k+2);

for(int i=1;i<=k;i++)

floyd();

for(int i=1;i<=m;i++)

for(int i=1;i<=n;i++)

printf("%d\n",m-ek.maxflow(0,ek.n-1));

if(t) puts("");

}return 0;

}

#include#include#include#include#include#include#include#define maxn 500

#define inf 0x3f3f3f3f

using namespace std;

int n,m,k;

mapstr;

bool map[210][210];

struct edge

};struct edmondskarp

}if(a[t]) break;

}if(!a[t]) break;

for(int u=t;u!=s;u=edges[p[u]].from)

flow+=a[t];

}return flow;

}void debug()

if(!i[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()

scanf("%d",&m);

for(int i=1;i<=m;i++)

scanf("%d",&k);

ek.init(n+m+2);

for(int i=1;i<=k;i++)

floyd();

for(int i=1;i<=m;i++)

for(int i=1;i<=n;i++)

ek.addedge(i+m,ek.n-1,1);

printf("%d\n",m-ek.maxflow(0,ek.n-1));

if(t) puts("");

}return 0;

}

#include#include#include#include#include#include#include#define maxn 500

#define inf 0x3f3f3f3f

using namespace std;

int n,m,k;

mapstr;

struct edge

};struct edmondskarp

}if(a[t]) break;

}if(!a[t]) break;

for(int u=t;u!=s;u=edges[p[u]].from)

flow+=a[t];

}return flow;

}void debug()

scanf("%d",&m);

for(int i=1;i<=m;i++)

scanf("%d",&k);

edmondskarp ek;

ek.init(n+m+k+2);

for(int i=1;i<=k;i++)

for(int i=1;i<=m;i++)

for(int i=1;i<=n;i++)

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);

printf("%d\n",m-ek.maxflow(0,ek.n-1));

if(t) puts("");

}return 0;

}

插頭Uva753 最大流

題意 n個插座和m個插頭,k種轉換器 每種都是無限個,可以把插頭轉換成其他型別的插頭 求最少剩多少個插頭沒插上插座。思路 首先給所有插頭或插座以及轉換器中涉及到的型別編號。然後根據轉換器建立型別之間的轉化關係,接著用floyd演算法算出每個裝置所有適配的型別,並將其容量設為inf,表示轉換器數量充足...

模板 網路最大流 最大流

給出乙個網路圖,以及其源點和匯點,求出其網路最大流。in put role presentation inp utin put4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40ou tput role presentation out puto utpu t50最大...

模板 網路最大流 最大流

給出乙個網路圖,以及其源點和匯點,求出其網路最大流。in put role presentation inp utin put4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40ou tput role presentation out puto utpu t50最大...