Codeforces Round #532 (Div. 2)E. Andrew and Taxi

题意:给一个有向图,反转某些边让这个图无环,反转的花费是反转的所有边中权值最大的,求花费最小的方式,输出花费和需要反转的边。

思路:把某个边反转其实就相当于把这条边删除,二分答案,用拓扑排序判断是否又环,最后删完了之后是ACG,求每个点的拓扑序,然后检验删去的边是否能形成环。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct code
{
    int x,y,z;
} edge[100005];
int vis[100005];
int deg[100005],n,m;
vector<int>dap[100005];
queue<int>p;
void init(int mid)
{
    for(int i=1; i<=n; i++)
    {
        deg[i]=0;
        dap[i].clear();
    }
    for(int i=1; i<=m; i++)
    {
        if(edge[i].z<=mid)
            continue;
        dap[edge[i].x].push_back(edge[i].y);
        deg[edge[i].y]++;
    }
}
bool ok()
{
    int tim=0;
    for(int i=1; i<=n; i++)
    {
        if(deg[i]==0)
            p.push(i);
    }
    while(!p.empty())
    {
        int u=p.front();
        p.pop();
        vis[u]=++tim;
        int len=dap[u].size();
        for(int i=0; i<len; i++)
        {
            int to=dap[u][i];
            deg[to]--;
            if(deg[to]==0)
                p.push(to);
        }
    }
    if(tim==n)
        return 1;
    else
        return 0;
}
int main()
{
    int l=0,r=1e9;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++)
        scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
    while(l<=r)
    {
        int mid=(l+r)/2;
        init(mid);
        if(ok())
            r=mid-1;
        else
            l=mid+1;
    }
    printf("%d ",l);
    int ans=0,s[100005];
    init(l);
    ok();
    for(int i=1; i<=m; i++)
    {
        if(edge[i].z>l)
            continue;
        if(vis[edge[i].x]<vis[edge[i].y])
            continue;
        s[ans++]=i;
    }
    printf("%d\n",ans);
    for(int i=0; i<ans; i++)
    {
        if(i==0)
            printf("%d",s[i]);
        else
            printf(" %d",s[i]);
    }
    printf("\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41049928/article/details/86474253