西电oj 1058 图论,贪心

西电oj 1058 图论,贪心

1058: 找子图

时间限制: 1 Sec  内存限制: 128 MB
提交: 15  解决: 11
[提交][状态][讨论版]

题目描述

现有一张无向图,有n个点m条边,每条边都有一个权值w,现要求从中找出一个子图,这个子图需满足以下特征:
1.子图可以为空。
2.若某条边的两个端点都在此子图中,则这条边在这个子图中。
3.若某条边的两个端点都不在此子图中,则这条边在这个子图外。
4.若某条边的两个端点一个在子图中,另一个不在,则这条边消失。
5.子图中所有边权值的和减去子图外所有边权值的和最大(不包含消失的边)。
输出这个最大值。

输入

多组数据

对于每组数据,第一行两个整数n,m(1<=n<=100000,1<=m<=500000)
接下来m行,每行三个整数u,v,w,表示在u和v间有一条权值为w的无向边(1<=u,v<=n,-1000<=w<=1000)

输出

 对于每组数据,输出答案。

样例输入

3 3
1 2 2
2 3 -1
1 3 3
2 1
1 2 -1

样例输出

4
1

题意:用c[u]记录从u出发的所有边的权值和。将原图分为子图u和子图v,ans=u的权值和-v的权值和=[(c[u1]+c[u2]+...+c[uN])-(c[v1]+c[v2]+...+c[vN])]/2;
对某子图u,所有c[u]的和=子图u里的边的权值和的两倍+u边界的边的权值和,因此,用c[u]的和-c[v]的和,边界被减掉了,剩下权值差的两倍,很好地处理了子图边界消失的情况。
对式子中,c[i]>0的点i加到子图u里,c[i]<0的点加到v里即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<string>
#include<math.h>
#include<cctype>

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
const double EPS=0.0000000001;
const double Pi=acos(-1.0);

ll c[maxn];
int n,m;

int main()
{
    while(cin>>n>>m){
        memset(c,0,sizeof(c));
        while(m--){
            int u,v;ll w;
            scanf("%d%d%lld",&u,&v,&w);
            c[u]+=w;c[v]+=w;
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            if(c[i]>0) ans+=c[i];
            else ans-=c[i];
        }
        ans/=2;
        cout<<ans<<endl;
    }
    return 0;
}
View Code
 
没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/4553372.html