来源:牛客网
题目描述
ghc很喜欢吃汤圆,但是汤圆很容易被粘(zhān)漏。
根据多年吃汤圆经验,ghc总结出了一套汤圆防漏理论:
互相接触的汤圆容易粘(zhān)在一起,并且接触面积不同,粘(zhān)在一起的粘(nián)度也不同。
当ghc要夹起一个汤圆时,这个汤圆和现在碗里与这个汤圆接触的所有汤圆之间的粘(nián)度的和,如果大于汤圆的硬度,这个汤圆就会被粘(zhān)漏。
今天ghc又要煮汤圆啦,今天要煮n个汤圆,并且摆盘的方法已经设计好:
汤圆按照编号,有m对汤圆互相接触,用xi, yi, zi表示编号为xi和yi的两个汤圆互相接触,粘(nián)度为zi。
汤圆当然是越软越好吃,但是ghc的厨艺只允许把所有汤圆煮成同样的硬度。那么,汤圆的硬度最小可以是多少,可以满足吃的
过程中,存在一种夹汤圆的顺序,使得没有汤圆会被粘(zhān)漏呢?
注意:
不考虑汤圆的重力作用;
不能同时夹多个汤圆;
吃完汤圆一定要喝点汤。
输入描述:
第一行是一个正整数T(≤ 5),表示测试数据的组数, 对于每组测试数据, 第一行是两个整数n,m(1≤ n,m≤ 100000), 接下来m行,每行包含三个整数xi, yi, zi(1≤ xi, yi ≤ n, xi ≠ yi, 1 ≤ zi ≤ 1000000), 同一对汤圆不会出现两次。
输出描述:
对于每组测试数据,输出一行,包含一个整数,表示汤圆硬度的最小值。
题解:
二分硬度,拓扑排序判断是否可行
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+7;
struct node
{
int to;ll cost;
};
vector<node>p[maxn];
queue<int>P;
ll a[maxn],zz[maxn];
bool vis[maxn];
int n,m,xx[maxn],yy[maxn];
bool pp(ll x)
{
for(int i=0;i<=n;i++)p[i].clear();
memset(a,0,sizeof(a));
for(int i=0;i<m;i++)
{
node e;e.to=yy[i];e.cost=zz[i];
p[xx[i]].push_back(e);
e.to=xx[i];
p[yy[i]].push_back(e);
a[xx[i]]+=zz[i];
a[yy[i]]+=zz[i];
}
int ans=0;memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(!vis[i]&&a[i]<=x)
{
ans++;
vis[i]=1;
for(int j=0;j<p[i].size();j++)
{
int to=p[i][j].to;ll z=p[i][j].cost;
a[to]-=z;
if(!vis[to]&&a[to]<=x)P.push(to),ans++,vis[to]=1;
}
}
}
while(!P.empty())
{
int v=P.front();P.pop();
for(int i=0;i<p[v].size();i++)
{
node e=p[v][i];
a[e.to]-=e.cost;
if(!vis[e.to]&&a[e.to]<=x)P.push(e.to),ans++,vis[e.to]=1;
}
}
if(ans==n)return 1;
return 0;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int x,y;ll z;
scanf("%d%d%lld",&x,&y,&z);
xx[i]=x;yy[i]=y;zz[i]=z;
}
ll l=-1,r=1e18;
while(r-l>1)
{
ll mid=(l+r)/2;
if(pp(mid))r=mid;
else l=mid;
}
printf("%lld\n",r);
}
return 0;
}