Dragons UVALive

来源:互联网 发布:linux dd备份 编辑:程序博客网 时间:2024/05/19 14:17

题目链接:https://vjudge.net/problem/UVALive-7018

题意:n个城市之间有m条路。共有K条龙,第Ki条龙住在Ci城市,初始有Si个头,只要他活着(头的数目不为0)每分钟会长出Ni个头。现要雇佣x名猎人去杀龙,每分钟每个猎人有两种选择:(1)在当前城市砍去龙的一个头;(2)沿着路去往相邻城市。求x的最小值。

思路:二分判断mid是否是最小的可行解。由于城市间共有m条路,有些城市可能是不可达的,这样n个城市可能变成若干个联通快,对每个连通块用二分求解出最小的可行解,所有连通块的最小可行解求和即可。可用并查集将城市根据是否联通分成若干连通块。训练赛时我给的思路学弟写的代码,思路错了两次坑他WA了两次,尴尬啊。

代码如下:

#include<iostream>#include<iomanip>#include<sstream>#include<string>#include<algorithm>#include<vector>#include<list>#include<stack>#include<map>#include<set>#include<queue>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>using namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;#define rep(a,b,c) for(int (a)=(b);(a)<=(c);(a)++)#define drep(a,b,c) for(int (a)=(c);(a)>=(b);(a)--)const int inf = 0x3f3f3f3f;const int maxn = 1000+10;int n,m,k;int meida[310];int da[310];int fa[310];vector<int>v[310];vector<pair<int,int> >vv[310];int id[310];int geshu;int vis[310];bool check(int mid,int x)//判断第x个联通块雇佣mid个猎人是否可行{        int cun=mid;        int sum=0;        bool ok = false;        int sz=v[x].size();        for(int j=0;j<sz;j++)        {            int t=v[x][j];            if(!vis[t]) continue;            else            {                int ssz=vv[t].size();                for(int k=0;k<ssz;k++)                {                    if(vv[t][k].second<mid) continue;//若增长速度小于猎人总数,一定可以杀死                    else sum+=vv[t][k].first;//若增长速度大于猎人总数,则初始龙头总数之和必须小于猎人总数才行                }            }        }        return mid>=sum;}int finds(int x){    return x==fa[x]?x:(fa[x]=finds(fa[x]));}int main(){    while(scanf("%d%d%d",&n,&m,&k)==3)    {        if(n==0&&m==0&&k==0) break;        for(int i=0;i<=n;i++)        {            v[i].clear();            vv[i].clear();        }        geshu=0;        memset(id,-1,sizeof(id));        memset(vis,0,sizeof(vis));        int a,b;        for(int i=0;i<=n;i++) fa[i]=i;        for(int i=0;i<m;i++)        {            scanf("%d%d",&a,&b);            int aa=finds(a);            int bb=finds(b);            if(aa!=bb) fa[aa]=bb;        }        for(int i=1;i<=n;i++)//并查集划分连通块,同一连通块内城市根节点相同        {            fa[i]=finds(fa[i]);        }        for(int i=1;i<=n;i++)        {            if(id[fa[i]]==-1) {id[fa[i]]=geshu++;v[geshu-1].push_back(i);}//为每个连通块编号并将城市放入对应连通块集合中            else v[id[fa[i]]].push_back(i);        }        int city,head,inc;        for(int i=0;i<k;i++)        {            scanf("%d%d%d",&city,&head,&inc);            vv[city].push_back(make_pair(head,inc));//每个城市可能有若干条龙            vis[city]=1;//标记该城市是否有龙        }        int sum=0;        for(int i=0;i<geshu;i++)//对每个连通块二分查找其最小可行解        {            int l=0,res,mid,r=inf;            while(l<=r)            {                mid=(l+r)/2;                if(check(mid,i)) {res=mid;r=mid-1;}                else l=mid+1;            }            sum+=res;//最小可行解求和        }        printf("%d\n",sum);    }    return 0;}