1. 程式人生 > >Educational Codeforces Round 55 (Rated for Div. 2) G Increasing Frequency(網路流 最大權閉合圖)

Educational Codeforces Round 55 (Rated for Div. 2) G Increasing Frequency(網路流 最大權閉合圖)

題目連結:http://codeforces.com/contest/1082/problem/G

G. Petya and Graph

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Petya has a simple graph (that is, a graph without loops or multiple edges) consisting of nn vertices and mm edges.

The weight of the ii-th vertex is aiai.

The weight of the ii-th edge is wiwi.

A subgraph of a graph is some set of the graph vertices and some set of the graph edges. The set of edges must meet the condition: both ends of each edge from the set must belong to the chosen set of vertices.

The weight of a subgraph is the sum of the weights of its edges, minus the sum of the weights of its vertices. You need to find the maximum weight of subgraph of given graph. The given graph does not contain loops and multiple edges.

Input

The first line contains two numbers nn and mm (1≤n≤103,0≤m≤1031≤n≤103,0≤m≤103) - the number of vertices and edges in the graph, respectively.

The next line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤1091≤ai≤109) - the weights of the vertices of the graph.

The following mm lines contain edges: the ii-e edge is defined by a triple of integers vi,ui,wivi,ui,wi (1≤vi,ui≤n,1≤wi≤109,vi≠ui1≤vi,ui≤n,1≤wi≤109,vi≠ui). This triple means that between the vertices vivi and uiui there is an edge of weight wiwi. It is guaranteed that the graph does not contain loops and multiple edges.

Output

Print one integer — the maximum weight of the subgraph of the given graph.

Examples

input

Copy

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

output

Copy

8

input

Copy

3 3
9 7 8
1 2 1
2 3 2
1 3 3

output

Copy

0

Note

In the first test example, the optimal subgraph consists of the vertices 1,3,41,3,4 and has weight 4+4+5−(1+2+2)=84+4+5−(1+2+2)=8. In the second test case, the optimal subgraph is empty.

題意:

給你n個點的權值和m帶權無向條邊(n,m<=1000),你要選出若干條邊,獲得的價值為邊權總和-點權總和

讀完這題感覺有點熟悉,於是...

發現我的部落格裡寫過幾乎是原題的題(只差在long long上):

HDU 3879 Base Station 最大權閉合圖

部落格:https://blog.csdn.net/lsd20164388/article/details/79224422

所以說 根本就是一個題了。。。只要看出來是個網路流就可以過了。。。(這道題的程式碼只需改改maxn就可以過HDU 3879了)

我是把hdu3879的程式碼改成了long long。。。就過了。。。

程式碼:

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define inf 0x3f3f3f3f3f3f3f3fLL
using namespace std;
const int maxn=60000+10;
struct edge
{
    int to,nxt;
    ll cap;
}g[maxn*10];
int head[maxn],pre[maxn],cur[maxn],gap[maxn],level[maxn];
int cnt,nv;
void add(int u,int v,ll cap)
{
    g[cnt].to=v;g[cnt].cap=cap;g[cnt].nxt=head[u];head[u]=cnt++;
    g[cnt].to=u;g[cnt].cap=0;g[cnt].nxt=head[v];head[v]=cnt++;
}
ll sap(int s,int t)
{
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    memcpy(cur,head,sizeof(head));
    gap[0]=nv;
    int v=pre[s]=s;
    ll flow=0,aug=inf;
    while(level[s]<nv)
    {
        bool flag=false;
        for(int &i=cur[v];i!=-1;i=g[i].nxt)
        {
            int u=g[i].to;
            if(g[i].cap>0&&level[v]==level[u]+1)
            {
                flag=true;
                pre[u]=v;
                v=u;
                aug=min(aug,g[i].cap);
                if(v==t)
                {
                    flow+=aug;
                    while(v!=s)
                    {
                        v=pre[v];
                        g[cur[v]].cap-=aug;
                        g[cur[v]^1].cap+=aug;
                    }
                    aug=inf;
                }
                break;
            }
        }
        if(flag) continue;
        int minlevel=nv;
        for(int i=head[v];i!=-1;i=g[i].nxt)
        {
            int u=g[i].to;
            if(g[i].cap>0&&minlevel>level[u])
            minlevel=level[u],cur[v]=i;
        }
        if(--gap[level[v]]==0) break;
        level[v]=minlevel+1;
        gap[level[v]]++;
        v=pre[v];
    }
    return flow;
}
int n,m,a,b;
ll c;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
    cnt=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&c);
        add(m+i,n+m+1,c);//每個基站向匯點連邊
    }
    ll sum=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&a,&b,&c);
        sum+=c;
        add(0,i,c);//源點和需求連邊
        add(i,m+a,inf);//需求和所要求的的基站連邊
        add(i,m+b,inf);
    }
    nv=n+m+2;
    printf("%lld\n",sum-sap(0,n+m+1));
    }
    return 0;
}