1. 程式人生 > >P2153 [SDOI2009]晨跑(最小費用最大流)

P2153 [SDOI2009]晨跑(最小費用最大流)

front 第一個 一個數 set ace include cpp radi n)

題目描述

Elaxia最近迷戀上了空手道,他為自己設定了一套健身計劃,比如俯臥撐、仰臥起坐等 等,不過到目前為止,他堅持下來的只有晨跑。 現在給出一張學校附近的地圖,這張地圖中包含N個十字路口和M條街道,Elaxia只能從 一個十字路口跑向另外一個十字路口,街道之間只在十字路口處相交。Elaxia每天從寢室出發 跑到學校,保證寢室編號為1,學校編號為N。 Elaxia的晨跑計劃是按周期(包含若幹天)進行的,由於他不喜歡走重復的路線,所以 在一個周期內,每天的晨跑路線都不會相交(在十字路口處),寢室和學校不算十字路 口。Elaxia耐力不太好,他希望在一個周期內跑的路程盡量短,但是又希望訓練周期包含的天 數盡量長。 除了練空手道,Elaxia其他時間都花在了學習和找MM上面,所有他想請你幫忙為他設計 一套滿足他要求的晨跑計劃。

存在1\rightarrow n1n的邊存在。這種情況下,這條邊只能走一次。

輸入輸出格式

輸入格式:

第一行:兩個數N,M。表示十字路口數和街道數。 接下來M行,每行3個數a,b,c,表示路口a和路口b之間有條長度為c的街道(單向)。

輸出格式:

兩個數,第一個數為最長周期的天數,第二個數為滿足最長天數的條件下最短的路程長 度。

輸入輸出樣例

輸入樣例#1: 復制
7 10
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
2 5 5
3 6 6
5 7 1
6 7 1
輸出樣例#1: 復制
2 11

說明

對於30%的數據,N ≤ 20,M ≤ 120。

對於100%的數據,N ≤ 200,M ≤ 20000。

題解:

其實就只是一個建邊的過程,我們需要拆點才能保證每個點都只訪問一次,

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN= 20000+10;
const int INF=0x3f3f3f3f;
struct Edge{
    int from,to,cap,flow,cost;
    Edge(int u,int v, int c,int f ,int w):from(u),to(v),cap(c),flow(f),cost(w)
    {}
};
struct MCMF
{
    int n,m;
    vector<Edge>edges;
    vector<int>G[MAXN];
    int inq[MAXN];
    int d[MAXN];
    int p[MAXN];
    int a[MAXN];
    void init(int n) {
        this->n=n;
        for (int i=0;i<=n;i++)G[i].clear();
        edges.clear();
    }
    void AddEdge(int from, int to,int cap,int cost)
    {
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool BellmanFord(int s,int t,int &flow,long long &cost){
        for(int i=0;i<=n;i++)d[i]=INT_MAX;
        memset(inq,0, sizeof(inq));
        d[s]=0;inq[s]=1;p[s]=0;a[s]=INT_MAX;
        queue<int >Q;
        Q.push(s);
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            inq[u]=0;
            int ll=G[u].size();
            for (int i = 0; i <ll ; ++i) {
                Edge& e=edges[G[u][i]];
                if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=G[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if(!inq[e.to]){Q.push(e.to);inq[e.to]=1;}
                }
            }
        }
        if(d[t]==INT_MAX) return false;
        flow+=a[t];
        cost+=(long long)d[t]*(long long )a[t];
        for (int u = t; u !=s ; u=edges[p[u]].from) {
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
    int MincostMaxflow(int s,int t,long long &cost){
        int flow=0;cost=0;
        while(BellmanFord(s, t, flow, cost));
        return flow;
    }

};
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int x,y,z;
    MCMF M;
    M.init(n+n);
    int s=1,t=n+n;
    M.AddEdge(1,n+1,INF,0);
    M.AddEdge(n,n+n,INF,0);
    for (int i = 2; i <n ; ++i) {
        M.AddEdge(i,i+n,1,0);
    }
    for (int i = 0; i <m ; ++i) {
        scanf("%d%d%d",&x,&y,&z);
        if(x==1&&y==n)
        {
            M.AddEdge(x+n,n,1,z);
        } else
        {
            M.AddEdge(x+n,y,1,z);
        }
    }
    LL cost=0;
    LL flow=M.MincostMaxflow(1,n+n,cost);
    printf("%lld %lld\n",flow,cost);
    return 0;
}

  

P2153 [SDOI2009]晨跑(最小費用最大流)