1. 程式人生 > >Codeforces 950E Data Center Maintenance ( 思維 && 強連通分量縮點 )

Codeforces 950E Data Center Maintenance ( 思維 && 強連通分量縮點 )

strong namespace print 出入度 const 最優 span 圖片 max

題意 : 給出 n 個點,每個點有一個維護時間 a[i]。m 個條件,每個條件有2個點(x,y)且 a[x] != a[y]。選擇最少的 k (最少一個)個點,使其值加1後,m個條件仍成立。

分析 :

發現改變某些數加一後可能產生聯動效應

換句話說就是改變某些數則必須改變另一些數來維持 m 個條件的成立

這個可以用圖來表示,對於給出來的每一個 (x, y) 如果改變 x 後等於 y 則連 x => y 邊

表示要改變 x 則必須改變 y,然後對於 y 進行同樣的判斷是否連邊

最後建完圖後,若有成環的,則這個環上的點要加一改變,則環上所有點都必須進行改變

因此將整個圖進行強連通分量縮點,最後考察所有出度為 0 的的分量,哪個分量點最少

則這個點集就是答案,出度不為 0 的點肯定不是最優的,因為這些點定會回到出度為 0 的點

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int maxm = 2e5 + 10;
struct EDGE{ int v, nxt; }Edge[maxm];
int Head[maxn], cnt;
int DFN[maxn], LOW[maxn], color[maxn], INDEX, id;
bool vis[maxn], out[maxn];
stack<int> stk;
vector
<int> num[maxn]; int N, M, H; inline void init() { while(!stk.empty()) stk.pop(); for(int i=0; i<=N; i++){ Head[i] = DFN[i] = LOW[i] = color[i] = -1; out[i] = false; num[i].clear(); }cnt = INDEX = id = 0; } inline void AddEdge(int from, int to) { Edge[cnt].v
= to; Edge[cnt].nxt = Head[from]; Head[from] = cnt++; } inline void tarjan(int u) { DFN[u] = LOW[u] = INDEX++; stk.push(u); vis[u] = true; for(int i=Head[u]; i!=-1; i=Edge[i].nxt){ int Eiv = Edge[i].v; if(DFN[Eiv] == -1){ tarjan(Eiv); LOW[u] = min(LOW[u], LOW[Eiv]); }else{ if(vis[Eiv]) LOW[u] = min(LOW[u], LOW[Eiv]); } } if(DFN[u] == LOW[u]){ color[u] = ++id; num[id].push_back(u);; vis[u] = false; while(stk.top() != u){ vis[stk.top()] = false; color[stk.top()] = id; num[id].push_back(stk.top()); stk.pop(); } stk.pop(); } } int arr[maxn]; int main(void) { scanf("%d %d %d", &N, &M, &H); init(); for(int i=1; i<=N; i++) scanf("%d", &arr[i]); int u, v; while(M--){ scanf("%d %d", &u, &v); if((arr[u]+1)%H == arr[v]) AddEdge(u, v); if((arr[v]+1)%H == arr[u]) AddEdge(v, u); } for(int i=1; i<=N; i++) if(DFN[i] == -1) tarjan(i);///強連通分量縮點 for(int i=1; i<=id; i++){///統計縮點後每個點的出入度情況 for(int j=0; j<num[i].size(); j++){ u = num[i][j]; for(int k=Head[u]; k!=-1; k=Edge[k].nxt){ int Eiv = Edge[k].v; if(color[Eiv] != i){ out[i] = true; break; } } if(out[i]) break; } } int MM = 0x3f3f3f3f, which; for(int i=1; i<=id; i++){ if(!out[i] && num[i].size() < MM){ MM = num[i].size(); which = i; } } printf("%d\n", MM); for(int i=1; i<=N; i++) if(color[i] == which) printf("%d ", i); puts(""); return 0; }
View Code

Codeforces 950E Data Center Maintenance ( 思維 && 強連通分量縮點 )