西电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; }
时间: 2024-10-06 06:48:17