E - E CodeForces - 1100E(拓撲排序 + 二分)

E - E CodeForces - 1100Eios

一個n個節點的有向圖,節點標號從1到n,存在m條單向邊。每條單向邊有一個權值,表明翻轉其方向所需的代價。求使圖變成無環圖,其中翻轉的最大邊權值最小的方案,以及該方案翻轉的最大的邊權。git

Input 單組輸入,第一行包含兩個整數n和m(2≤n≤100 000,1≤m≤100 000) 接下來m行,每行3個整數,u_i ,v_i
,w_i (1<= u_i , v_i <= n, 1<= w_i <=
10^9),表示u到v有一條權值爲w的道路。道路編號從1開始。沒有自環。spa

Output 在第一行中輸出兩個整數,即要翻轉的最大的邊權,和須要反轉道路數量k。k不須要是最小的。code

在下一行輸出k個由空格分隔的整數,表示須要翻轉的道路編號blog

若是有許多解決方案,請打印其中任何一個。排序

Examples
Input
5 6
2 1 1
5 2 6
2 3 2
3 4 3
4 5 5
1 5 4
Output
2 2
1 3 
Input
5 7
2 1 5
3 2 3
1 3 3
2 4 1
4 3 5
5 4 1
1 5 3
Output
3 3
3 4 7

思路

  • 題意:給我一個有向帶權值的圖,這個圖可能存在環,問所需改變的反轉的邊的最小權全是多少?
  • 思路:首先用二分枚舉,要反轉邊的最大邊權的最小值mid,都一個所給的圖中的邊中 邊權小於mid 把這個邊視爲雙向邊(不存在),而後在剩下的子圖中 跑一邊 拓撲排序, 看是否有環的存在,若是有的話讓 讓 l = mid + 1, 不然 r = mid - 1
  • 連接

題解

#include<iostream>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
#define int long long
#define inf 10000000000000
using namespace std;
int read(){
    int res=0;char ch=0;
    while (!isdigit(ch))ch=getchar();
    while (isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}

const int N=1000100;
struct EDGE{
    int ver,nxt,dis,pre;
}edge[N];
int n,m,cnt,head[N],vis[N],d[N],ans[N],dfn[N],dfs_cnt;

void add(int u,int v,int t){
    edge[++cnt].ver=v;
    edge[cnt].nxt=head[u];
    edge[cnt].dis=t;
    edge[cnt].pre=u;
    head[u]=cnt;
}

queue<int>q;
bool check(int x){

    memset(d,0,sizeof(d));memset(vis,0,sizeof(vis));

    for (int i=1;i<=m;i++)if(edge[i].dis>x)d[edge[i].ver]++;

    for (int i=1;i<=n;i++)if (!d[i])q.push(i);

    while (!q.empty()){

        int u=q.front();q.pop();

        for (int i=head[u];i;i=edge[i].nxt)
        {
            if (edge[i].dis<=x)continue;

            int v=edge[i].ver;d[v]--;if (!d[v])q.push(v);
        }
    }

    for (int i=1;i<=n;i++)if (d[i])return 0;

    return 1;
}
void solute(int x){
    memset(d,0,sizeof(d));memset(vis,0,sizeof(vis));

    for (int i=1;i<=m;i++)if(edge[i].dis>x)d[edge[i].ver]++;
    for (int i=1;i<=n;i++)if (!d[i])q.push(i);

    while (!q.empty())
    {
        int u=q.front();q.pop();dfn[u]=++dfs_cnt;

        for (int i=head[u];i;i=edge[i].nxt)
        {
            if (edge[i].dis<=x)continue;
            int v=edge[i].ver;d[v]--;if (!d[v])q.push(v);
        }
    }

    for (int i=1;i<=m;i++){
        if (edge[i].dis<=x){
            int u=edge[i].pre,v = edge[i].ver;
            if (dfn[u]>dfn[v])ans[++cnt]=i;
        }
    }
}
signed main(){
    n=read();m=read();
    for (int i=1;i<=m;i++){
        int x=read(),y=read(),t=read();add(x,y,t);
    }
    int l=0,r=inf;
    while (l<r)
    {
        int mid=l+r>>1;
        if (check(mid))
            r=mid;
        else
            l=mid+1;
    }

    cnt=0;
    solute(r);
    printf("%lld %lld\n",r,cnt);
    for (int i=1;i<=cnt;i++){
        printf("%lld ",ans[i]);
    }
}
相關文章
相關標籤/搜索