• BZOJ2163: 复杂的大门


    BZOJ2163: 复杂的大门

    Description

    你去找某bm玩,到了门口才发现要打开他家的大门不是一件容易的事……
    他家的大门外有n个站台,用1到n的正整数编号。你需要对每个站台访问一定次数以后大门才能开启。

    站台之间有m个单向的传送门,通过传送门到达另一个站台不需要花费任何代价。

    而如果不通过传送门,你就需要乘坐公共汽车,并花费1单位的钱。值得庆幸的是,任意两个站台之间都有公共汽车直达。
    现在给你每个站台必须访问的次数Fi,对于站台i,你必须恰好访问Fi次(不能超过)。
    我们用u、v、w三个参数描述一个传送门,表示从站台u到站台v有一个最多可以使用w次的传送门(不一定要使用w次)。

    值得注意的是,对于任意一对传送门(u1,v1)和(u2,v2),如果有u1<u2,则有v1≤v2;如果有v1<v2,则有u1≤u2;且u1=u2和v1=v2不同时成立。
    你可以从任意的站台开始,从任意的站台结束。出发去开始的站台需要花费1单位的钱。你需要求出打开大门最少需要花费多少单位的钱。

    Input

    第一行包含两个正整数n、m,意义见题目描述。第二行包含n个正整数,第i个数表示Fi。

    接下来有m行,每行有三个正整数u、v、w,表示从u到v有一个可以使用w次的传送门。

    Output

    输出一行一个整数,表示打开大门最少花费的钱数。

    Sample Input

    4 3
    5 5 5 5
    1 2 1
    3 2 1
    3 4 1

    Sample Output

    17

    HINT

    有20%的数据满足n≤10,m≤50;对于所有的w、Fi,满足1≤w,Fi≤10。

    有50%的数据满足n≤1000,m≤10000。100%的数据满足1≤n≤10000,1≤m≤100000;对于所有的u、v,满足1≤u,v≤n,u≠v;对于所有的w、Fi,满足1≤w,Fi≤50000。

    以上的每类数据中都存在50%的数据满足对于所有的w、Fi,有w=Fi=1。


    题解Here!
    这个题乍一看好像没有什么思路。
    最多使用$w$次?感觉像网络流。。。
    我们可以先把模型转换为计算最大使用传送门的次数。
    这不就是最大流嘛。。。
    拆点没的说。。。
    对于每个$i$,拆成$i$和$i+n$,然后从$S$到$i$连一条流量为要求达到访问次数的边,$i+n$到$T$也连一条容量为要求达到访问次数的边。
    然后对于每个传送门,由$u$到$v+n$连容量为传送门使用次数$w$的边。
    跑出最大流就是最大使用传送门的次数。
    然后用所有的点要求达到的访问次数的总和减去最大流就好了。 
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 100010
    #define MAX 999999999
    using namespace std;
    int n,m,s,t,c=2,sum=0;
    int head[MAXN],deep[MAXN];
    struct Graph{
        int next,to,w;
    }a[MAXN<<1];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void add(int u,int v,int w){
        a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
        a[c].to=u;a[c].w=0;a[c].next=head[v];head[v]=c++;
    }
    bool bfs(){
        int u,v;
        queue<int> q;
        for(int i=s;i<=t;i++)deep[i]=0;
        deep[s]=1;
        q.push(s);
        while(!q.empty()){
            u=q.front();
            q.pop();
            for(int i=head[u];i;i=a[i].next){
                v=a[i].to;
                if(a[i].w&&!deep[v]){
                    deep[v]=deep[u]+1;
                    if(v==t)return true;
                    q.push(v);
                }
            }
        }
        return false;
    }
    int dfs(int x,int limit){
        if(x==t)return limit;
        int v,sum,cost=0;
        for(int i=head[x];i;i=a[i].next){
            v=a[i].to;
            if(a[i].w&&deep[v]==deep[x]+1){
                sum=dfs(v,min(a[i].w,limit-cost));
                if(sum>0){
                    a[i].w-=sum;
                    a[i^1].w+=sum;
                    cost+=sum;
                    if(cost==limit)break;
                }
                else deep[v]=-1;
            }
        }
        return cost;
    }
    int dinic(){
        int ans=0;
        while(bfs())ans+=dfs(s,MAX);
        return ans;
    }
    void work(){
        int ans;
        ans=sum-dinic();
        printf("%d
    ",ans);
    }
    void init(){
        int u,v,w;
        n=read();m=read();
        s=0;t=(n<<1)+1;
        for(int i=1;i<=n;i++){
            w=read();
            sum+=w;
            add(s,i,w);add(i+n,t,w);
        }
        for(int i=1;i<=m;i++){
            u=read();v=read();w=read();
            add(u,v+n,w);
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    瞬间从IT屌丝变大神——HTML规范
    瞬间从IT屌丝变大神——命名规则
    瞬间从IT屌丝变大神——分工安排
    写在开发前的话
    完全二叉树的权值
    无法更改电脑默认浏览器
    java语法错误,进行分析时已经到达文件结尾
    查找SHA1值
    关闭CPU 睿频方法
    Java idea 快捷键
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9476928.html
Copyright © 2020-2023  润新知