bnu十六屆程式設計競賽決賽F-貪心|二分最大值最小化-湯圓防漏理論
阿新 • • 發佈:2018-12-24
題目描述
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),
同一對湯圓不會出現兩次。
輸出描述:
對於每組測試資料,輸出一行,包含一個整數,表示湯圓硬度的最小值。
示例1
輸入
1
4 6
1 2 2
1 3 2
1 4 2
2 3 3
2 4 3
3 4 5
輸出
6
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+6;
typedef long long ll;
vector<pair<int,int> >g[maxn];
ll val[maxn];
ll vv[maxn];
int m;
bool vis[maxn];
bool bfs(ll sum){
queue<int>q;
for(int i=1;i<=m;i++){
vv[i]=val[i];
}
//cout<<endl;
memset(vis,false,sizeof(vis));
for(int i=1;i<=m;i++){
if(vv[i]<=sum){
q.push(i),vis[i]=true;
//cout<<i<<">??"<<vv[i];
}
}
//q.push(1);vis[1]=true;
ll rel=-1;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=true;
rel=max(rel,vv[u]);
for(int i=0;i<g[u].size();i++){
int to=g[u][i].first;
if(vis[to]) continue;
vv[to]-=g[u][i].second;
q.push(to);
}
}
if(rel<=sum&&rel!=-1)return true;//後來分了兩種情況,一種是沒有進入佇列,rel為-1,另一種為進入佇列rel不為-1,還不對。
return false;
}
int main()
{
int t,a,b,c,mm;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&mm);
memset(val,0,sizeof(val));
//!!!!!!
for(int i=0;i<maxn;i++)g[i].clear();
for(int i=0;i<mm;i++){
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
val[a]+=c;
val[b]+=c;
}
//sort(val,val+m);
ll bigst=-1;
for(int i=0;i<m;i++){
bigst=max(bigst,val[i]);
}
ll r=bigst*2;
ll l=0;
while(l<r){
ll mid=(l+r)/2;
// cout<<mid<<endl;
if(bfs(mid))
r=mid-1;
else
l=mid+1;
}
ll ans=0;
if(bfs(l)) ans=l;
if(bfs(r)) ans=min(ans,r);
printf("%lld\n",ans);
}
return 0;
}
②二分正解:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+6;
typedef long long ll;
vector<pair<int,int> >g[maxn];
ll val[maxn];
ll vv[maxn];
int m;
bool vis[maxn];
bool bfs(ll sum){
queue<int>q;
for(int i=1;i<=m;i++){
vv[i]=val[i];
}
memset(vis,false,sizeof(vis));
for(int i=1;i<=m;i++){
if(vv[i]<=sum){
q.push(i),vis[i]=true;
}
}
//q.push(1);vis[1]=true;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<g[u].size();i++){
int to=g[u][i].first;
if(to==u)continue;
if(vis[to]) continue;
vv[to]-=g[u][i].second;
if(vv[to]<=sum){
vis[to]=true;
q.push(to);
}
}
}
int sums=0;
for(int i=1;i<=m;i++){
if(vis[i])
sums++;
}
if(sums==m)return true;
return false;
}
int main()
{
int t,a,b,c,mm;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&mm);
memset(val,0,sizeof(val));
for(int i=0;i<maxn;i++)g[i].clear();
for(int i=0;i<mm;i++){
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
val[a]+=c;
val[b]+=c;
}
ll bigst=-1;
for(int i=0;i<m;i++){
bigst=max(bigst,val[i]);
}
ll r=bigst*2;
ll l=0;
while(l<=r){
ll mid=(l+r)/2;
if(bfs(mid))
r=mid-1;
else
l=mid+1;
}
ll ans=0;
if(bfs(l)) ans=l;
if(bfs(r)) ans=min(ans,r);
printf("%lld\n",ans);
}
return 0;
}
③貪心
#include <bits/stdc++.h>
using namespace std;
/* 這個是貪心的原理,
每次放最小的。最有可能把最大的慢慢給拆掉,
而每次放最大的,則不會。
*/
const int maxn=1e5+5;
typedef long long ll;
#define mp make_pair
vector<pair<int,ll> >g[maxn];
struct Node{
int to;
ll va;
Node(int _to,ll _va){
to=_to;
va=_va;
}
bool operator<(const Node &b)const{
return (this->va<b.va);//用Node各種超時,氣死我了
}
};
set<pair<ll,int> >se;
ll du[maxn];
bool vis[maxn];
int main()
{ int t;
scanf("%d",&t);
int m,n,a,b;
ll c;
while(t--){
scanf("%d%d",&m,&n);
for(int i=0;i<=m;i++) {g[i].clear();
du[i]=0;
}
for(int i=0;i<n;i++){
scanf("%d%d%lld",&a,&b,&c);
g[a].push_back(mp(b,c));
g[b].push_back(mp(a,c));
du[a]+=c;
du[b]+=c;
}
se.clear();
for(int i=1;i<=m;i++){
se.insert(mp(du[i],i));
vis[i]=false;
}
ll ans=0;
for(int i=1;i<=m;i++){
int to=se.begin()->second;
ans=max(ans,du[to]);
se.erase(se.begin());
vis[to]=true;
for(int j=0;j<g[to].size();j++){
int tos=g[to][j].first;
if(vis[tos])continue;
se.erase(mp(du[tos],tos));
du[tos]-=g[to][j].second;
se.insert(mp(du[tos],tos));
}
}
printf("%lld\n",ans);
}
return 0;
}