codeforces1100E. Andrew and Taxi(二分+拓扑)

  给n个点,m条边,然后每个边有个权值,然后需要把一些边反向使得图中无环,问你需要反向的边的最大边权最小是多少?

  写这题需要知道拓扑排序的一个应用,当原图是无环的,在a,b两点之间加一条有向边,还得保证图是环的,加的边的方向取决与topo[a],topo[b],若topo[a]<topo[b],那么就是a到b的边,否则相反。

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define PI acos(-1)
#define eps 1e-8
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
typedef pair<int,int> pii;
const int inf=2e9;
const int maxn=1e5+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
//int lowbit(int x){return x&-x;}
//void add(int x,int v){while(x<=n)bit[x]+=v,x+=lowbit(x);}
//int sum(int x){int ans=0;while(x>=1) ans+=bit[x],x-=lowbit(x);return ans;}
inline ll read() {
    ll s = 0,w = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(isdigit(ch))
        s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
inline void write(ll x) {
    if(x < 0)
        putchar('-'), x = -x;
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}
struct edge{
    int u,v,w;
}e[maxn];

vector<int>g[maxn];
vector<int>ans,tmp;
queue<int>q;
int n,m,in[maxn],topo[maxn];

bool check(int mid){
    tmp.clear();
    for(int i=1;i<=n;i++) g[i].clear(),in[i]=0;
    for(int i=1;i<=m;i++){
        if(e[i].w>mid)
            g[e[i].u].push_back(e[i].v),in[e[i].v]++;
    }
    for(int i=1;i<=n;i++)
        if(in[i]==0)
            q.push(i);
    int cnt=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        topo[u]=++cnt;
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            in[v]--;
            if(in[v]==0) q.push(v);
        }
    }
    if(cnt!=n) return false;
    for(int i=1;i<=m;i++){
        if(e[i].w<=mid)
            if(topo[e[i].u]>topo[e[i].v])
                tmp.push_back(i);
    }
    return true;
}

int main(){
    n=read();
    m=read();
    for(int i=1;i<=m;i++){
        e[i].u=read();
        e[i].v=read();
        e[i].w=read();
    }
    int low=0,high=1e9,mid,minn;
    while(low<=high){
        mid=(low+high)>>1;
        if(check(mid)){
            minn=mid;
            high=mid-1;
            ans=tmp;
        } else
            low=mid+1;
    }
    printf("%d %d\n",minn,ans.size());
    for(int i=0;i<ans.size();i++)
        printf("%d ",ans[i]);
    puts("");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40642465/article/details/102977831