1. 程式人生 > >BZOJ_1266_[AHOI2006]上學路線route_最小割

BZOJ_1266_[AHOI2006]上學路線route_最小割

ahoi2006 printf r++ scan 輸入 設計 bds namespace tmp

BZOJ_1266_[AHOI2006]上學路線route_最小割

Description

可可和卡卡家住合肥市的東郊,每天上學他們都要轉車多次才能到達市區西端的學校。直到有一天他們兩人參加了學校的信息學奧林匹克競賽小組才發現每天上學的乘車路線不一定是最優的。 可可:“很可能我們在上學的路途上浪費了大量的時間,讓我們寫一個程序來計算上學需要的最少時間吧!” 合肥市一共設有N個公交車站,不妨將它們編號為1…N的自然數,並認為可可和卡卡家住在1號汽車站附近,而他們學校在N號汽車站。市內有M條直達汽車路線,執行第i條路線的公交車往返於站點pi和qi之間,從起點到終點需要花費的時間為ti。(1<=i<=M, 1<=pi, qi<=N) 兩個人坐在電腦前,根據上面的信息很快就編程算出了最優的乘車方案。然而可可忽然有了一個鬼點子,他想趁卡卡不備,在卡卡的輸入數據中刪去一些路線,從而讓卡卡的程序得出的答案大於實際的最短時間。而對於每一條路線i事實上都有一個代價ci:刪去路線的ci越大卡卡就越容易發現這個玩笑,可可想知道什麽樣的刪除方案可以達到他的目的而讓被刪除的公交車路線ci之和最小。 [任務] 編寫一個程序: ? 從輸入文件中讀取合肥市公交路線的信息; ? 計算出實際上可可和卡卡上學需要花費的最少時間; ? 幫助可可設計一個方案,刪除輸入信息中的一些公交路線,使得刪除後從家到學校需要的最少時間變大,而被刪除路線的ci和最小;向輸出文件輸出答案。

Input

輸入文件中第一行有兩個正整數N和M,分別表示合肥市公交車站和公交汽車路線的個數。以下M行,每行(第i行,總第(i+1)行)用四個正整數描述第i條路線:pi, qi, ti, ci;具體含義見上文描述。

Output

輸出文件最多有兩行。 第一行中僅有一個整數,表示從可可和卡卡家到學校需要的最短時間。 第二行輸出一個整數C,表示Ci之和

Sample Input

6 7
1 2 1 3
2 6 1 5
1 3 1 1
3 4 1 1
4 6 1 1
5 6 1 2
1 5 1 4

Sample Output

2
5

HINT

2<=N<=500, 1<=M<=124 750, 1<=ti, ci<=10 000

合肥市的公交網絡十分發達,你可以認為任意兩個車站間都可以通過直達或轉車互相到達,當然如果在你提供的刪除方案中,家和學校無法互相到達,那麽則認為上學需要的最短為正無窮大:這顯然是一個合法的方案。


只保留原圖中最短路上的邊,這樣只要讓1和n不連通就相當於最短路變長了。

於是求最小割即可。

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define N 550
#define M 300050
#define inf 100000000
int head[N],to[M],nxt[M],dis[N][2],val[M],flow[M],cnt,n,m,xx[M],yy[M],zz[M],cc[M];
int Q[N],l,r,dep[N],vis[N];
__gnu_pbds::priority_queue<pair<int,int> >q;
inline void add(int u,int v,int w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
inline void insert(int u,int v,int f) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f;
    to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0;
}
void dij() {
    memset(dis,0x3f,sizeof(dis));
    dis[1][0]=0; q.push(make_pair(0,1));
    int i;
    while(!q.empty()) {
        int x=q.top().second; q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(i=head[x];i;i=nxt[i]) {
            if(dis[to[i]][0]>dis[x][0]+val[i]) {
                dis[to[i]][0]=dis[x][0]+val[i];
                q.push(make_pair(-dis[to[i]][0],to[i]));
            }
        }
    }
    memset(vis,0,sizeof(vis)); dis[n][1]=0; q.push(make_pair(0,n));
    while(!q.empty()) {
        int x=q.top().second; q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(i=head[x];i;i=nxt[i]) {
            if(dis[to[i]][1]>dis[x][1]+val[i]) {
                dis[to[i]][1]=dis[x][1]+val[i];
                q.push(make_pair(-dis[to[i]][1],to[i]));
            }
        }
    }
}
bool bfs() {
    memset(dep,0,sizeof(dep));
    l=r=0;Q[r++]=1;dep[1]=1;
    while(l<r) {
        int x=Q[l++],i;
        for(i=head[x];i;i=nxt[i]) {
            if(!dep[to[i]]&&flow[i]) {
                dep[to[i]]=dep[x]+1;
                if(to[i]==n) return 1;
                Q[r++]=to[i];
            }
        }
    }
    return 0;
}
int dfs(int x,int mf) {
    if(x==n) return mf;
    int nf=0,i;
    for(i=head[x];i;i=nxt[i]) {
        if(dep[to[i]]==dep[x]+1&&flow[i]) {
            int tmp=dfs(to[i],min(mf-nf,flow[i]));
            if(!tmp) dep[to[i]]=0;
            nf+=tmp;
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            if(nf==mf) break;
        }
    }
    return nf;
}
void dinic() {
    int ans=0,f;
    while(bfs()) while(f=dfs(1,inf)) ans+=f;
    printf("%d\n",ans);
}
int main() {
    scanf("%d%d",&n,&m);
    int i;
    for(i=1;i<=m;i++) {
        scanf("%d%d%d%d",&xx[i],&yy[i],&zz[i],&cc[i]);
        add(xx[i],yy[i],zz[i]);
        add(yy[i],xx[i],zz[i]);
    }
    dij();
    memset(head,0,sizeof(head)); cnt=1;
    int len=dis[n][0];
    printf("%d\n",len);
    for(i=1;i<=m;i++) {
        if(dis[xx[i]][0]+dis[yy[i]][1]+zz[i]==len) {
            insert(xx[i],yy[i],cc[i]);
        }
        if(dis[yy[i]][0]+dis[xx[i]][1]+zz[i]==len) {
            insert(yy[i],xx[i],cc[i]);
        }
    }
    dinic();
}

BZOJ_1266_[AHOI2006]上學路線route_最小割