E. Andrew and Taxi(二分+拓撲判環)
阿新 • • 發佈:2019-01-14
題目連結:http://codeforces.com/contest/1100/problem/E
題目大意:給你n和m,n代表有n個城市,m代表有m條邊,然後m行輸入三個數,起點,終點,花費。,每一條邊的花費指的是將這條路方向反轉的花費。然後問你使得整個圖沒有環的最小花費。(這裡的最小花費指的是改變方向的邊中,權值最大的那個)。
具體思路:二分答案,我們找出符合題目條件的最優解,check的時候,建立邊權大於當前值的邊,我們是通過形成的圖判斷有沒有環來檢驗的,找到最優解之後,將剩餘邊權的大於最優解的邊建立一個圖,然後進行拓撲排序。再列舉每一條邊,看這一條邊的起點和終點的拓撲序,如果說起點的拓撲序大於終點的拓撲序,也就是說這條邊應該是方向翻轉,然後找出這滿足情況的邊就可以了。
反思:
1.這樣為什麼可以呢?昨晚打比賽的時候想到了一種情況,就是如果將當前的一條邊翻轉之後,原來的圖中的環會不再存在,但是會形成新的圖,這樣的話也是不行的,但是對於這種情況,畫畫圖就知道了,這種情況的話,外面肯定是有一個大環的,我們只需要對這個大環進行操作就可以了(操作的邊數沒有限制,只要這條邊權比當前二分的值小就可以了)。
AC程式碼:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 #include <cstring> 6#include <ctime> 7 #include <algorithm> 8 #include <map> 9 #include <vector> 10 #include <queue> 11 using namespace std; 12 # define ll long long 13 # define pi acos(-1.0) 14 const int maxn = 1e5+100; 15 int deg[maxn],head[maxn],ord[maxn],vis[maxn]; 16 int num,n,m;17 vector<int>qq; 18 struct node 19 { 20 int fr; 21 int to; 22 int nex; 23 int cost; 24 } q[maxn],edge[maxn*2]; 25 void init() 26 { 27 num=0; 28 memset(head,-1,sizeof(head)); 29 memset(deg,0,sizeof(deg)); 30 } 31 void addedge(int fr,int to) 32 { 33 edge[num].to=to; 34 edge[num].nex=head[fr]; 35 head[fr]=num++; 36 deg[to]++; 37 } 38 bool check(int t) 39 { 40 memset(vis,0,sizeof(vis)); 41 init(); 42 for(int i=1; i<=m; i++) 43 { 44 if(q[i].cost>t) 45 addedge(q[i].fr,q[i].to); 46 } 47 queue<int>wakaka; 48 for(int i=1;i<=n;i++){ 49 if(deg[i]==0){ 50 wakaka.push(i); 51 } 52 } 53 while(!wakaka.empty()){ 54 int top=wakaka.front(); 55 wakaka.pop(); 56 vis[top]=1; 57 for(int i=head[top];i!=-1;i=edge[i].nex){ 58 int u=edge[i].to; 59 if(--deg[u]==0)wakaka.push(u); 60 } 61 } 62 for(int i=1;i<=n;i++){ 63 if(vis[i]==0)return false;//(拓撲判環) 64 } 65 return true; 66 } 67 int main() 68 { 69 scanf("%d %d",&n,&m); 70 for(int i=1; i<=m; i++) 71 { 72 scanf("%d %d %d",&q[i].fr,&q[i].to,&q[i].cost); 73 } 74 int l=0,r=1e9; 75 while(l<r) 76 { 77 int mid=(l+r)/2; 78 if(check(mid)) 79 { 80 r=mid; 81 } 82 else 83 l=mid+1; 84 } 85 init(); 86 for(int i=1; i<=m; i++) 87 { 88 if(q[i].cost>r) 89 { 90 addedge(q[i].fr,q[i].to); 91 } 92 } 93 queue<int>wakaka; 94 for(int i=1; i<=n; i++) 95 { 96 if(!deg[i]) 97 wakaka.push(i); 98 } 99 memset(ord,0,sizeof(ord)); 100 int ans=0; 101 while(!wakaka.empty()) 102 { 103 int top=wakaka.front(); 104 wakaka.pop(); 105 ord[top]=++ans; 106 for(int i=head[top]; i!=-1; i=edge[i].nex) 107 { 108 int to=edge[i].to; 109 deg[to]--; 110 if(!deg[to]) 111 { 112 wakaka.push(to); 113 } 114 } 115 } 116 for(int i=1; i<=m; i++) 117 { 118 if(ord[q[i].fr]>ord[q[i].to])//(拓撲序) 119 { 120 qq.push_back(i); 121 } 122 } 123 printf("%d %d\n",r,qq.size()); 124 int len=qq.size(); 125 for(int i=0; i<len; i++) 126 { 127 if(i==0) 128 printf("%d",qq[i]); 129 else 130 printf(" %d",qq[i]); 131 } 132 printf("\n"); 133 return 0; 134 }