1. 程式人生 > >5438(拓撲排序+dfs)

5438(拓撲排序+dfs)

題目大意

給出無向圖,可以刪除只有一個點相連的結點,然後剩下一些強連通分量,如果一個強連通分量中結點個數為奇數則把他們的價值加到ans中

思路

先用拓撲排序刪點,把能刪的點都刪了,然後在跑dfs統計一個強連通中結點的個數。

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (int)1e4 + 100;
const int maxm = (int)1e5 + 100;

struct Edge {
    int to;
    int Next;
};
int n,
m, sz; ll cnt, sum; int head[maxm<<1], in[maxn], val[maxn]; bool isdel[maxn], vis[maxn]; Edge edge[maxm<<1]; void addEdge(int u, int v) { edge[sz].to = v; edge[sz].Next = head[u]; head[u] = sz++; // 標記頭結點的 } void init() { sz=0; memset(head, -1, sizeof(head)); memset
(in, 0, sizeof(in)); memset(vis, false, sizeof(vis)); memset(isdel, false, sizeof(isdel)); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &val[i]); } for(int i = 0, u, v; i < m; i++) { scanf("%d%d", &u, &v); addEdge
(u, v); addEdge(v, u); in[u]++; in[v]++; } } void topo() { queue<int> qu; for(int i = 1; i <= n; i++) { if(in[i]<=1) { qu.push(i); } } while(!qu.empty()) { int u = qu.front(); qu.pop(); if(isdel[u]) continue; isdel[u] = true; for(int i = head[u]; i != -1; i = edge[i].Next) { int v = edge[i].to; in[v]--; if(in[v]<=1&&!isdel[v]) { qu.push(v); } } } } void dfs(int u) { // dfs搜尋強連通分量的結點數 vis[u] = true; sum += val[u]; cnt++; for(int i=head[u];i!=-1; i=edge[i].Next) { if(!isdel[edge[i].to] && !vis[edge[i].to]) { dfs(edge[i].to); } } } int main() { //freopen("input.txt", "r", stdin); int T; scanf("%d", &T); while(T--) { init(); topo(); ll ans = 0; for(int i = 1; i <= n; i++) { if(!isdel[i] && !vis[i]) { sum = 0, cnt = 0; dfs(i); if(cnt % 2) { ans += sum; } } } cout << ans << endl; } return 0; }