Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2868 | Accepted: 823 |
Description
Input
Output
Sample Input
9 3 1 1 1 2 2 2 1 1 1 1 2 1 2 3 2 1 2 1 1 1 1 2 2 2 1 1 1
Sample Output
3
Hint
fewer than three lifts.
有一段时间没写SCC了,纯手打一发,没想到1A了。
题意:有一个L*W的田地,每个位置都有一定的高度。若a处高度 >= b处高度,则a可以到达b(不代表b可达a)。现在问你最少增加几条边使图中任意两个位置都可以互相可达。
思路:求出SCC,缩点后。求出出度为0的SCC数目ans1,入度为0的SCC数目ans2。答案就是max(ans1, ans2)。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <stack> #include <vector> #include <algorithm> #define MAXN 250000+10 #define MAXM 1000000+10 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int low[MAXN], dfn[MAXN]; int dfs_clock; int sccno[MAXN], scc_cnt; stack<int> S; bool Instack[MAXN]; int W, L; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } int point(int x, int y) { return (x-1) * W + y; } void addEdge(int u, int v) { Edge E = {u, v, head[u]}; edge[edgenum] = E; head[u]= edgenum++; } bool judge(int x, int y) { return x >= 1 && x <= L && y >= 1 && y <= W; } int Map[510][510]; void getMap() { int move[4][2] = {0,1, 0,-1, 1,0, -1,0}; for(int i = 1; i <= L; i++)// W L不要反了 { for(int j = 1; j <= W; j++) scanf("%d", &Map[i][j]); } for(int i = 1; i <= L; i++) { for(int j = 1; j <= W; j++) { for(int k = 0; k < 4; k++) { int x = i + move[k][0]; int y = j + move[k][1]; if(judge(x, y) && Map[x][y] <= Map[i][j]) addEdge(point(i, j), point(x, y)); } } } } void tarjan(int u, int fa) { int v; low[u] = dfn[u] = ++dfs_clock; S.push(u); Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { scc_cnt++; for(;;) { v = S.top();S.pop(); Instack[v] = false; sccno[v] = scc_cnt; if(u == v) break; } } } void find_cut(int l, int r) { memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(sccno, 0, sizeof(sccno)); memset(Instack, false, sizeof(Instack)); dfs_clock = scc_cnt = 0; for(int i = l; i <= r; i++) if(!dfn[i]) tarjan(i, -1); } int out[MAXN], in[MAXN]; void suodian() { for(int i = 1; i <= scc_cnt; i++) in[i] = out[i] = 0; for(int i = 0; i < edgenum; i++) { int u = sccno[edge[i].from]; int v = sccno[edge[i].to]; if(u != v) out[u]++, in[v]++; } } void solve() { find_cut(1, W*L); if(scc_cnt == 1)//注意 { printf("%d\n", 0); return ; } suodian(); int ans1 = 0, ans2 = 0; for(int i = 1; i <= scc_cnt; i++) { if(in[i] == 0) ans1++; if(out[i] == 0) ans2++; } printf("%d\n", max(ans1, ans2)); } int main() { while(scanf("%d%d", &W, &L) != EOF) { init(); getMap(); solve(); } return 0; }