1. 程式人生 > >[BZOJ 1266] 上學路線Route

[BZOJ 1266] 上學路線Route

pro esp 所有 www 沒有 flow 從後往前 amp https

Link:

BZOJ 1266 傳送門

Solution:

好不容易自己寫出來一道水題,練鏈式前向星的模板調了一小時o(╯□╰)o

思路非常好想,既然要想讓最短路不成立,使最短路部分不連通即可

又要求最小代價,就是比較明顯的最小割模型了

Tips:

1、關於如何快速將所有最短路部分重新建圖

既然$n<=500$,直接上$floyd$,只要判斷邊的兩端到1與$n$的最短距離加上邊權的和是否為最短路距離即可

但一旦$n$增大後能如何簡便處理呢?我想到的可以建反圖從後往前跑一遍,檢查每一條邊是否屬於任意一條最短路

但對於此題可以簡便處理:正向判斷$dist[x]+l(x,y)$是否為$dist[y]$即可

我們沒有必要只篩選出最短路的邊,只要保證非最短路到不了終點即可,算是用時間換代碼長度吧2333

2、對於鏈式前向星實現的網絡流算法

(1)$edge$數組的下標一定要從0開始,這樣才能使得$edge[i]$與$edge[i^1]$互為反邊

(2)由於上一條原則,$head$數組一定要初始化為-1,而不是-1與0皆可

以前只用$vector$寫還是不太行啊……

Code:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=505,MAXM=MAXN*MAXN,INF=1<<27;
int n,m,f[MAXN][MAXN];
struct data{int x,y,t,c;}dat[MAXM]; namespace Max_Flow //最大流 { int head[MAXN],S,T,level[MAXN],iter[MAXN],tot=-1; //數組坐標一定要從0開始 struct edge{int nxt,to,cap;}e[MAXM<<2]; void add_edge(int from,int to,int cap) { e[++tot].nxt=head[from];e[tot].to=to;e[tot].cap=cap;head[from
]=tot; e[++tot].nxt=head[to];e[tot].to=from;e[tot].cap=0;head[to]=tot; } bool bfs() { memset(level,-1,sizeof(level)); queue<int> q;q.push(S);level[S]=0; while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i!=-1;i=e[i].nxt) if(e[i].cap && level[e[i].to]==-1) level[e[i].to]=level[u]+1,q.push(e[i].to); } return (level[T]!=-1); } int dfs(int v,int f) { if(v==T) return f; int ret=0; for(int &i=iter[v];i!=-1;i=e[i].nxt) { if(level[e[i].to]==level[v]+1 && e[i].cap) { int d=dfs(e[i].to,min(f,e[i].cap)); e[i].cap-=d;e[i^1].cap+=d; f-=d;ret+=d;if(!f) break; } } return ret; } int Dinic() { int ret=0; while(bfs()) { for(int i=0;i<MAXN;i++) iter[i]=head[i]; ret+=dfs(S,INF); } return ret; } } int main() { using namespace Max_Flow; scanf("%d%d",&n,&m); memset(f,0x3f,sizeof(f));S=1;T=n; for(int i=1;i<=n;i++) f[i][i]=0; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&dat[i].x,&dat[i].y,&dat[i].t,&dat[i].c); int x=dat[i].x,y=dat[i].y; f[x][y]=f[y][x]=dat[i].t; } for(int k=1;k<=n;k++) //最短路部分 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=min(f[i][j],f[i][k]+f[k][j]); printf("%d\n",f[1][n]); memset(head,-1,sizeof(head)); //head一定要賦為-1 for(int i=1;i<=m;i++) { int x=dat[i].x,y=dat[i].y; if(f[1][x]+dat[i].t+f[y][n]==f[1][n]) add_edge(x,y,dat[i].c); if(f[1][y]+dat[i].t+f[x][n]==f[1][n]) add_edge(y,x,dat[i].c); } printf("%d\n",Dinic()); return 0; }

[BZOJ 1266] 上學路線Route