网络流/费用流+Floyed
Orz zyf
题解:
这题和星际竞速还有打印机两题的主体思路都是一样的
每个点一定要经过,并且要经过这个点,必须经过比这个点小的所有点。而且还存在一个附加源,但源到附加源有一定的容量限制(星际没有。。。)
这题我们采用如下方式建图:
1.把每个点拆成 i 和 i+n 两个点,分别表示从这个点出发和进入这个点
2.由s向所有i 连容量为1,费用为0的边
2.由所有i+n到t连容量为1,费用为0的边
3.由 i 向所有 j+n(j>n)连容量为1,费用为从 i 到 j,不经过比j标号大的中间节点的最短路 的边 (否则这条道路将不合法)
正确性可以从i+n 入流的来源来考虑,每一种流法都代表着一种实实在在的、合法的方案,cost就是花费时间,我们要时间最短,自然要最小费用最大流了
还有一个问题就是
费用为从 i 到 j,不经过比j标号大的中间节点的最短路 怎么求?
我自己yy了一种想法,如下:
for(int k=0;k<=n;k++) for(int i=0;i<=n;i++) for(int j=k;j<=n;j++) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
意思就是不使用比 j 大的节点作为中间节点来更新 i(1..n)到j的最短路
所以这个过程结束后,f[i][j]就代表着从 i 到 j不经过比 j大的节点的最短路
这种每个点都要经过一遍的题目好像都可以拆点搞二分图模型?
1 /************************************************************** 2 Problem: 2324 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:196 ms 7 Memory:6052 kb 8 ****************************************************************/ 9 10 //BZOJ 2324 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=410,M=200000,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n,m,k,mp[151][151]; 32 LL ans; 33 struct edge{int from,to,v,c;}; 34 struct Net{ 35 edge E[M]; 36 int head[N],next[M],cnt; 37 void ins(int x,int y,int z,int c){ 38 E[++cnt]=(edge){x,y,z,c}; 39 next[cnt]=head[x]; head[x]=cnt; 40 } 41 void add(int x,int y,int z,int c){ 42 ins(x,y,z,c); ins(y,x,0,-c); 43 } 44 int from[N],Q[M],d[N],S,T,ss; 45 bool inq[N]; 46 bool spfa(){ 47 int l=0,r=-1; 48 F(i,1,T) d[i]=INF; 49 d[S]=0; Q[++r]=S; inq[S]=1; 50 while(l<=r){ 51 int x=Q[l++]; 52 inq[x]=0; 53 for(int i=head[x];i;i=next[i]) 54 if(E[i].v>0 && d[x]+E[i].c<d[E[i].to]){ 55 d[E[i].to]=d[x]+E[i].c; 56 from[E[i].to]=i; 57 if (!inq[E[i].to]){ 58 Q[++r]=E[i].to; 59 inq[E[i].to]=1; 60 } 61 } 62 } 63 return d[T]!=INF; 64 } 65 void mcf(){ 66 int x=INF; 67 for(int i=from[T];i;i=from[E[i].from]) 68 x=min(x,E[i].v); 69 for(int i=from[T];i;i=from[E[i].from]){ 70 E[i].v-=x; 71 E[i^1].v+=x; 72 } 73 ans+=x*d[T]; 74 } 75 void init(){ 76 n=getint(); m=getint(); k=getint(); 77 cnt=1;ans=0; 78 int x,y,z; 79 F(i,0,n)F(j,0,n) mp[i][j]=INF; 80 F(i,1,m){ 81 x=getint(); y=getint(); z=getint(); 82 mp[x][y]=min(mp[x][y],z); 83 mp[y][x]=min(mp[y][x],z); 84 } 85 S=0; ss=2*n+1; T=2*n+2; add(S,ss,k,0); 86 F(k,0,n) F(i,0,n) F(j,k,n) 87 mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]); 88 F(i,1,n) add(S,i,1,0), 89 add(ss,i+n,1,mp[0][i]), 90 add(i+n,T,1,0); 91 F(i,1,n) F(j,i+1,n) 92 add(i,j+n,1,mp[i][j]); 93 while(spfa()) mcf(); 94 printf("%lld ",ans); 95 } 96 }G1; 97 98 int main(){ 99 #ifndef ONLINE_JUDGE 100 freopen("2324.in","r",stdin); 101 freopen("2324.out","w",stdout); 102 #endif 103 G1.init(); 104 return 0; 105 }