prologue
相信很多人都感觉这个题不就是求一下这个二分图的最大独立集嘛,有什么难的,(劈里啪啦、库里跨啦、叮里哐啷)好,不对,好好好,题解!
analysis
这个题目实际上并不是一个完整的最大独立集问题,因为在这个题里面,是可以有相互仇恨的骑士的,只要不让他们二人坐成同桌就行。
那么我们就不如从正面来解决这个题。
首先,建立这个 憎恨 关系的 补图 从而得到一张 友善 关系图,这个时候肯定会形成环,我们进行下一步的思考。
之后,用 tarjan 将每个图所成一个点,之后对于每一个内部点数大于等于三的 V-DCC 进行判断内部是不是 奇环(题目中有描述,每次会议只能是奇数个人),如果这个环内部的数量不是奇数,那么这环内部的骑士就不能参与会议,属于要被除名的人。
对于判断每一个环是不是奇环,我们可以用 染色法,如果发生 冲突 则代表内部是合法的,如果成功染色,则是 非法 的。
同时还有一个重要结论虽然我不知道为什么重要,大佬说是就是:点双连通图中若包含一个奇环,则所有点都在至少一个简单奇环上。
至于证明过程,大家可以前往巨佬的博客查看。
CODE TIME
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rl register ll
const ll N = 1010;
ll n, m;
ll dfn[N], low[N], top, timestamp, ans, tmp[N];
ll stk[N], dcc_cnt, dcc_size[N], col[N], root, now;
bool g[N][N], val[N], in_dcc[N], flag;
vector<ll> dcc[N];
inline void dfs(ll u, ll c)
{
if(flag) return ;
col[u] = c;
for(rl i=1; i <= n; ++ i) if(g[u][i])
{
if(tmp[i] != now) continue;
if(col[i]) if(col[i] == c) { flag = 1; return ;}
if(!col[i]) dfs(i, 3 - c);
}
}
inline void tarjan(ll u)
{
stk[ ++ top] = u;
dfn[u] = low[u] = ++ timestamp;
for(rl v=1; v <= n; ++ v)
{
if(!g[u][v]) continue;
if(!dfn[v])
{
tarjan(v), low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
{
dcc_cnt ++ ;
ll ele;
do {
ele = stk[top -- ];
dcc[dcc_cnt].push_back(ele), dcc_size[dcc_cnt] ++ ;
} while(ele != v);
dcc[dcc_cnt].push_back(u), dcc_size[dcc_cnt] ++;
}
}
else low[u] = min(low[u], dfn[v]);
}
}
inline void clean()
{
for(rl i=1; i <= dcc_cnt; ++ i) dcc[i].clear();
top = timestamp = dcc_cnt = ans = 0;
memset(dcc_size, 0, sizeof dcc_size), memset(dfn, 0, sizeof dfn), memset(tmp, 0, sizeof tmp);
memset(g, 0, sizeof g), memset(col, 0, sizeof col), memset(val, 0, sizeof val);
}
int main()
{
while(cin >> n >> m, n)
{
clean();
for(rl i=1; i <= n; ++ i) g[i][i] = 1;
for(rl i=1; i <= m; ++ i)
{
ll a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
}
for(rl i=1; i <= n; ++ i)
for(rl j=1; j <= n; ++ j)
g[i][j] ^= 1;
for(root = 1; root <= n; ++ root)
if(!dfn[root])
tarjan(root);
for(rl i=1; i <= dcc_cnt; ++ i)
{
now = i, flag = 0;
for(rl j : dcc[i]) tmp[j] = now, col[j] = 0;
dfs(dcc[i][0], 1);
if(flag)
for(rl j : dcc[i])
val[j] = true;
}
for(rl i=1; i <= n; ++ i) ans += val[i];
cout << n - ans << endl;
}
return 0;
}
标签:cnt,ll,dcc,ele,奇环,Table,rl,Knights,Round
From: https://www.cnblogs.com/carp-oier/p/17730505.html