2 条题解

  • 0
    @ 2022-07-27 16:18:11

    “H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。
    H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
    现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
    请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。”

    是树么

  • 0
    @ 2020-01-23 16:09:53

    想法上是做一个二分答案+贪心,然后用倍增来优化时间复杂度,但最后搞不出来,下面的代码只能通过8个测试数据点。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=50000+5;
    const int INF=0x3f3f3f3f;
    int n,m,a[maxn],g[maxn];
    struct node {
        int from,to,z;
    } edge[maxn*2];
    int head[maxn],vis[maxn],fa[maxn][16],cnt=0,tot=0,on[maxn],sh[maxn],f[maxn],c[maxn],b[maxn];
    ll dis[maxn][16],d[maxn];
    vector<ll>arv[maxn];
    void add(int from,int to,int z) {
        edge[++cnt].to=to;
        edge[cnt].z=z;
        edge[cnt].from=head[from];
        head[from]=cnt;
    }
    void bfs() {
        queue<int>q;
        vis[1]=1;
        for(int i=head[1]; i!=-1; i=edge[i].from) {
            int y=edge[i].to;
            q.push(y);
            vis[y]=1;
            b[++tot]=i;
            sh[y]=tot;
        }
        while(!q.empty()) {
            int x=q.front();
            q.pop();
            for(int i=head[x]; i!=-1; i=edge[i].from) {
                int y=edge[i].to;
                int z=edge[i].z;
                if(!vis[y]) {
                    vis[y]=1;
                    q.push(y);
                    dis[y][0]=z;
                    fa[y][0]=x;
                    for(int j=1; j<=15; j++) {
                        fa[y][j]=fa[fa[y][j-1]][j-1];
                        dis[y][j]=dis[fa[y][j-1]][j-1]+dis[y][j-1];
                    }
                }
            }
        }
    }
    bool dfs(int x) {
        vis[x]=1;
        if(!sh[x]&&on[x]) return 1;
        bool flag=0;
        for(int i=head[x]; i!=-1; i=edge[i].from) {
            int y=edge[i].to;
            if(!vis[y]) {
                flag=1;
                if(!dfs(y)) return 0;
            }
        }
        return flag;
    }
    bool solve(ll T) {
        memset(vis,0,sizeof(vis));
        memset(on,0,sizeof(on));
        vis[1]=1;
        for(int i=1; i<=tot; i++) {
            //arv[i].clear();
            while(arv[i].size()) arv[i].pop_back();
        }
        for(int i=1; i<=m; i++) {
            g[i]=a[i];
            d[i]=0;
            for(int j=15; j>=0; j--) {
                if(d[i]+dis[g[i]][j]<=T&&fa[g[i]][j]) {
                    d[i]+=dis[g[i]][j];
                    g[i]=fa[g[i]][j];
                }
            }
            on[g[i]]=1;
            /*
            if(T==56750) {
                cout<<g[i]<<endl;
            }
            */
            if(sh[g[i]]) { //到了根节点的子节点
                int j=sh[g[i]];
                arv[j].push_back(T-d[i]);
                if(arv[j].size()>1&&arv[j][arv[j].size()-1]>arv[j][arv[j].size()-2]) {
                    swap(arv[j][arv[j].size()-1],arv[j][arv[j].size()-2]);
                }
            }
        }
        int p=0,q=0;
        for(int i=1; i<=tot; i++) {
            int z=edge[b[i]].z;
            if(!dfs(edge[b[i]].to)) {
                if(arv[i].size()>0&&arv[i][arv[i].size()-1]<z*2) arv[i].pop_back();
                else f[++p]=z;
            }
            for(int j=0; j<arv[i].size(); j++) {
                if(arv[i][j]>=z) c[++q]=arv[i][j]-z;
            }
        }
        if(p>q) return false;
        sort(f+1,f+p+1);
        sort(c+1,c+q+1);
        for(int i=p,j=q; i; i--,j--) {
            if(f[i]>c[j]) return false;
        }
        return true;
    }
    int main() {
        ios::sync_with_stdio(false);
        //freopen("疫情控制.in","r",stdin);
        memset(head,-1,sizeof(head));
        cin>>n;
        int x,y,z;
        ll sum=0;
        for(int i=1; i<=n-1; i++) {
            cin>>x>>y>>z;
            add(x,y,z);
            add(y,x,z);
            sum+=z;
        }
        cin>>m;
        for(int i=1; i<=m; i++) {
            cin>>a[i];
        }
        bfs();
        ll l=0,r=sum+1;
        while(l<r) {
            ll mid=(l+r)>>1;
            if(solve(mid)) r=mid;
            else l=mid+1;
        }
        if(r==sum+1) cout<<-1;
        else cout<<l;
        return 0;
    }
    
    • @ 2020-01-23 16:10:38

      该题来自noip,想做出来的同学可以去百度一下这道题。

    • @ 2020-01-23 16:12:52

      my vegetable explode,自己做不出来。

  • 1

信息

ID
1123
难度
8
分类
贪心 | 数据结构 点击显示
标签
递交数
56
已通过
6
通过率
11%
上传者