1. 程式人生 > >bnu十六屆程式設計競賽決賽F-貪心|二分最大值最小化-湯圓防漏理論

bnu十六屆程式設計競賽決賽F-貪心|二分最大值最小化-湯圓防漏理論

題目描述 
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;
}