18.8.18NOIP模拟。。。。Snow

Noip模拟—-Snow

题目

有一天,TT 要去 ABC 家。ABC 的大门外有 n 个站台,用 1 到 n 的正整数编号,TT 需要对每个站台访问恰好一定次数以后才能到 ABC 家。站台之间有 m 个单向的传送门,通过传送门到达另一个站台不需要花费任何代价。而如果不通过传送门,TT 就需要乘坐公共汽车,并花费 1 单位的钱。值得庆幸的是,任意两个站台之间都有公共汽车直达。

现在给定每个站台必须访问的次数,对于站台 i ,TT 必须恰好访问 Fi 次(不能超过)。

我们用 u,v,w 三个参数描述一个传送门,表示从站台 u 到站台 v 有一个最多可以使用 w 次的传送门(不一定要使用 w 次)。对于任意一对传送门 (u1,v1) 和 (u2,v2),如果有 u1 < u2,则有v1 ≤ v2;如果有 v1 < v2 ,则有 u1 ≤ u2;且 u1=u2 和 v1=v2 不同时成立。

TT 可以从任意的站台开始,从任意的站台结束。出发去开始的站台需要花费 1 单位的钱。现在请帮助 TT 求出打开大门最少需要花费多少单位的钱。

输入格式
第一行包含两个正整数 n,m,意义见题目描述。
第二行包含 n 个正整数,第 i 个数表示 Fi。
接下来有 m 行,每行有三个正整数 u,v,w,表示从 u 到 v 有一个可以使用 w 次的传送门。

输出格式
输出仅一行包含一个整数表示答案。

样例数据 1
输入 

4 3
5 5 5 5
1 2 1
3 2 1
3 4 1
输出

17
备注
【数据范围】
有 20% 的数据满足 n≤10,m≤50;
有 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。

做法有好多好多好多种;

随便列几种

1、跑有上下界的最小费用流(期望50~100,不稳定)
2、跑有上下界的最小流
3、求出加权的最小路径覆盖,每个点设两个,变成一个二分图,跑最大流
4、平面图的最小割
5、一种炒鸡厉害的线性复杂度动态规划

4、5要用到一种叫最小左转法的算法造点,反正什么那啥乱七八糟的就不管了,

直接上自己的代码
开始是直接把自己的最大流板子抄上来,结果发现不对,一查发现自己的板子是错的,然而板子交上去仍然能A,肯定是数据太水了 滑稽(划掉)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch;
    while((ch=getchar())<'0'||ch>'9'){;}
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
    res=res*10+ch-'0';
    return res;
}
int adj[200005],nxt[1000005],to[1000005],dep[100005],cap[1000005],cur[100005],f[100005],str,cnt=-1,n,m,des;
inline void addedge(int u,int v,int w){
    nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
    nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline bool bfs(){
    int qn=1,que[100005],u,v,e;
    que[qn]=str;
    memset(dep,-1,sizeof(dep));
    for(int i=1;i<=n;i++) cur[i]=adj[i];
    dep[str]=0;
    for(int ql=1;ql<=qn;ql++)
    {
        u=que[ql];
        for(e=adj[u];e!=-1;e=nxt[e])
        {
            if(cap[e]>0&&dep[v=to[e]]==-1)
            {
                dep[v]=dep[u]+1,que[++qn]=v;
                if(v==des) return true;
            }
        }
    }
    return false;
}
inline int dfs(const int &u,const int &flow)
{
    if(u==des||!flow) return flow;
    int res=0,v,flw;
    for(int e=adj[u];e!=-1;e=nxt[e])
    {
        if(cap[e]>0&&dep[v=to[e]]==dep[u]+1)
        {
            flw=dfs(v,min(cap[e],flow-res));
            if(flw==0) dep[v]=-1;
            cap[e]-=flw,cap[e^1]+=flw;//因为有个e^1,所以初始cnt要设为-1; 
            res+=flw;if(res==flow) break;
        }
    }
    return  res;
}
inline int solve(){
    int as=0;
    while(bfs()) as+=dfs(str,1<<30);
    return as;
}
int main(){
    n=read(),m=read();
    str=0,des=2*n+1;
    int ans=0;
    memset(adj,-1,sizeof(adj));
    for(int i=1;i<=n;i++)
    {
        f[i]=read();addedge(str,i,f[i]),addedge(i+n,des,f[i]);
        ans+=f[i];
    }
    int u,v,w;
    for(int i=1;i<=m;i++)
    {
        u=read(),v=read(),w=read();
        addedge(u,v+n,w);
    }
    cout<<ans-solve()<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/81810472