zoukankan      html  css  js  c++  java
  • 北京师范大学第十六届程序设计竞赛决赛 F 汤圆防漏理论

    链接:https://www.nowcoder.com/acm/contest/117/F
    来源:牛客网

    汤圆防漏理论
    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld

    题目描述

    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 N = 1e5 + 5;
    
    using LL = long long;
    using P = pair<LL, int>;
    
    LL cnt[N];
    int n, m;
    
    set<P> edge[N];
    
    priority_queue<P, vector<P>, greater<P> > Q;
    
    void Work()
    {
        LL ans = 0;
        for(int i = 1; i <= n; i++)
        {
            Q.push({cnt[i], i});
        }
        while(!Q.empty())
        {
            auto tmp = Q.top(); Q.pop();
            if(tmp.first != cnt[tmp.second]) continue;
            int u = tmp.second;
            ans = max(ans, tmp.first);
            for(auto p : edge[u])
            {
                int v = p.second;
                cnt[v] -= p.first;
                edge[v].erase({p.first, u});
                Q.push({cnt[v], v});
            }
        }
        cout << ans << endl;
    }
    
    int main()
    {
       int T;
       cin >> T;
       while(T--)
       {
           cin >> n >> m;
           for(int i = 1; i <= n; i++) 
           {
                edge[i].clear();
                cnt[i] = 0;
           }
    
           int u, v, w;
           for(int i = 1; i <= m; i++)
           {
                cin >> u >> v >> w;
                cnt[u] += w;
                cnt[v] += w;
                edge[u].insert({w, v});
                edge[v].insert({w, u});
           }
           Work();
       }
    
    }
    #include<cstdio>
    #include<cmath>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define ll      long long
    #define N       100000
    #define mod     1000000007
    #define pa      pair<ll,ll>
    vector<pa>g[N+5];
    set<pa>p;
    ll sum[N+5];        //表示编号为i的人的粘稠度综合
    bool vis[N+5];      //去重
    int main()
    {
        int i,j,t,q,n,m,a,b,w,x;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++)        //p不需要清了,本来就是空的
            {
                g[i].clear();
                sum[i]=0;
                vis[i]=false;
            }
            while(m--)
            {
                scanf("%d%d%d",&a,&b,&w);
                g[a].push_back(pa(b,w));
                g[b].push_back(pa(a,w));    //将a,b连接起来
                sum[a]+=w;
                sum[b]+=w;
            }
            for(i=1;i<=n;i++)
                p.insert(pa(sum[i],i));     //将数据输入到set
            ll maxd=0; 
            while(!p.empty())           //贪心
            {
                set<pa>::iterator it=p.begin();
                pa now= *it;    //now.first表示他的粘稠度,now,second表士坐标
                p.erase(*it);
                maxd=max(now.first,maxd);
            //  printf("%lld  now.first=%lld
    ",maxd,now.first);
                x=now.second;
                vis[x]=true;            //标记   
                //第一步,删除权值的边
                for(i=0;i<g[x].size();i++)
                {
                    pa l=g[x][i];           //为了理解,再写下,l.first是x对应的边
                    if(vis[l.first])
                        continue;
                    p.erase(pa(sum[l.first],l.first));
                    sum[l.first]-=l.second;
                    p.insert(pa(sum[l.first],l.first));
                }
                 
            }
            printf("%lld
    ",maxd);
        }
         
        return 0;
    }
    View Code
    题解:  
    二分硬度,拓扑排序判断是否可行  
    代码:  
    #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
    ",r);  
        }  
        return 0;  
    }  
  • 相关阅读:
    分享一个Fluent风格的邮件发送封装类
    写一个ActionFilter检测WebApi接口请求和响应
    一道有趣的面试题,小鸟和火车的问题
    Centos7 查看Mysql配置文件
    Centos7 grep命令简介
    Centos7 网络配置
    django之python3.4及以上连接mysql的一些问题记录
    NetCore log4net 集成以及配置日志信息不重复显示或者记录
    ionic3中关于Ionic ui component使用的一些总结
    ionic2升级到ionic3并打包APK
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/9094207.html
Copyright © 2011-2022 走看看