arc111d

arc111d

大意

略。。。

思路

如果 (a)(b) 连有向边,那么,所有 (b) 能访问到的点, (a) 都能访问到,此时一定有 (c_b leq c_a)

显然,对于一对顶点 ((i,j)) ,如果出现 (c_i != c_j) ,那么, (c) 大的一定会朝 (c) 小的连边。

对于 (c_i == c_j) 的情况,能发现,原图中出现了一个环。

我们只需要用 dfs 找出这个环并标记上就好了。

不难发现环之外的部分连边方案唯一,对于环来说,有多种联通方案。

如果你是在寻找环时将当前的节点与将要去的节点的连边方案保存下来的 dfs 做法,那么要注意,

  1. 是否会有两个节点之间的边未考虑到(比如一条路径的首尾相连)
  2. 是否会出现回溯时修改了已经确定的结果(比如一条路径的首尾相连)

这都是用大量时间为代价得出的注意点...

代码

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)

const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

int n, m;
bool mp[101][101];
bool ans[100100]; // 1 means ->
bool vis[101];
int edge[100100][2];
int c[100];
bool ans1[101][101];

void dfs(cint loc) {
    vis[loc] = 1;
    for(int i=1; i<=n; i++)
        if(mp[loc][i] && c[i] == c[loc]) {
            ans1[loc][i] = 1;
            mp[loc][i] = mp[i][loc] = 0;
            if(!vis[i]) dfs(i);
        }
}

int main() {
    cin >> n >> m;
    for(int i=1; i<=m; i++) cin >> edge[i][0] >> edge[i][1];
    for(int i=1; i<=m; i++) mp[edge[i][0]][edge[i][1]] = mp[edge[i][1]][edge[i][0]] = 1;
    for(int i=1; i<=n; i++) cin >> c[i];
    for(int i=1; i<=m; i++) {
        int l = edge[i][0], r = edge[i][1];
        if(c[l] != c[r]) ans1[l][r] = c[l] > c[r];
        else if(!vis[r]) dfs(r);
        ans[i] = ans1[l][r];
    }
    for(int i=1; i<=m; i++)
        if(ans[i]) cout << "->" << endl;
        else cout << "<-" << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/ullio/p/14562258.html