HDU3844Tour (好題)
阿新 • • 發佈:2017-10-12
inf strong else ret turn cnblogs oid ont ace
題意: 有N個點,M個單向邊,現在要你設計N條路線覆蓋所有的點,每個點都屬於且值屬於一個環。(為什麽是N條邊:和最小生成樹為什麽有N-1條邊是一樣的證明)。
解析: 每個點都有一個喜歡對象(出度)和被喜歡對象(入度),故將一個點拆成男點和女點,然後用最佳匹配即可!
坑die:有重邊!MMP
(好像還可以用網絡流來解決,容我想兩天)
HDU3844
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<memory.h>
#include<algorithm>
#include <cmath>
using namespace std;
const int maxn=310;
const int inf=0x7ffffff;
int map[maxn][maxn];
int vis1[maxn],vis2[maxn];
int ex1[maxn],ex2[maxn];
int lack[maxn];
int link[maxn];
int ans,n;
int x1[maxn],x2[maxn],y[maxn],y2[maxn];
int Abs(int v){
if(v<0) v=-v;
return v;
}
bool _bfs(int v)
{
vis1[v] =true;
for(int i=1;i<=n;i++){
if(!vis2[i]){
int tmp=ex1[v]+ex2[i]-map[v][i];
if(tmp==0){
vis2[i]=true;
if(!link[i]||_bfs(link[i])){
link[i]=v;
return true;
}
}
else if(tmp<lack[i]) lack[i]=tmp;
}
}
return false;
}
void _KM()
{
int t,i,j;
memset(link,0,sizeof(link));
memset(ex2,0,sizeof(ex2));
for(i=1;i<=n;i++){
ex1[i]=map[i][1];
for(j=2;j<=n;j++)
if(ex1[i]<map[i][j]) ex1[i]=map[i][j];
}
for(t=1;t<=n;t++){
for(i=1;i<=n;i++) lack[i]=inf;
while(true){
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
if(_bfs(t)) break;
int gap=inf;
for(i=1;i<=n;i++)
if(!vis2[i]&&lack[i]<gap) gap=lack[i];
for(i=1;i<=n;i++) if(vis1[i]) ex1[i]-=gap;
for(i=1;i<=n;i++) if(vis2[i]) ex2[i]+=gap;
for(i=1;i<=n;i++) if(!vis2[i])lack[i]-=gap;
}
}
ans=0;
for(i=1;i<=n;i++)
ans-=map[link[i]][i];
ans=ans;
printf("%d\n",ans);
}
int main()
{
int i,j,m,T,u,v,w;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) map[i][j]=inf;
for(i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
if(w<map[u][v]) map[u][v]=w;//消滅重邊
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)map[i][j]=-map[i][j];
_KM();
}
return 0;
}
HDU3844Tour (好題)