您的位置:首页 > 其它

HDU_6073 Matching In Multiplication 【二分图&&拓扑排序&&DFS】

2017-08-10 08:18 375 查看
题目链接

题目描述

如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图。准确地说:把一个图的顶点划分为两个不相交集 U 和V ,使得每一条边都分别连接U、V中的顶点。如果存在这样的划分,则此图为一个二分图。二分图的一个等价定义是:不含有「含奇数条边的环」的图完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。但是小Q错误的理解了二分图的定义,以为二分图的两个顶点集u和v的大小相等,u中的每个顶点p都可以引出两条边,它定义了一个二分图的权重就是每个完美匹配的权重相加,每个完美匹配的权重是这个完美匹配中所有边的乘积。

解题思路

首先如果一个点的度数为1,那么它的匹配方案是固定的,继而我们可以去掉这一对点。通过拓扑我们可以不断去掉所有度数为1的点。那么剩下的图中左右各有m个点,每个点度数都不小于2,且左边每个点度数都是2,而右侧总度数是2m,因此右侧只能是每个点度数都是2。这说明这个图每个连通块是个环,在环上间隔着取即可,一共两种方案。

代码部分

#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int N = 300000 + 10;
struct Edge {
int nxt, to, w;
bool mrk;
} e[N*4];///构造领接链表的边结点
int T, n, head[N*2], cnt, deg[N*2], used[N*2];
///T表示测试数据的组数,n表示节点个数,head表示头结点,deg记录每个结点的度,used表示这个节点是否被匹配过
long long part[2];///part表示最后剩的那两部分
void addedge(int u, int v, int w) {///构造领接链表
e[++cnt].nxt = head[u];
e[cnt].to = v;
e[cnt].w = w;
e[cnt].mrk = 0;
head[u] = cnt;
}
void dfs(int cur, int idx) {
///因为要隔着取所以我们可以用part[0]表示一种情况,part[1]表示另一种情况,然后每次改变idx的值
used[cur] = 1;///表示这个顶点已经找过了,不能再找,所以要标记一下
for(int i=head[cur];i;i=e[i].nxt)
{
if(e[i].mrk)    continue;///如果这个顶点已经被用了,就跳过
e[i].mrk = e[i^1].mrk = 1;///没有则标记,并把它对应的那个点也标记了
(part[idx] *= e[i].w) %= mod;///每个完美匹配的累乘
dfs(e[i].to, 1-idx);///递归寻找另一个完美匹配边
}
}
int main()
{
scanf("%d", &T);
while(T-- && scanf("%d", &n)!=EOF)
{
memset(head, 0, sizeof(head));
memset(deg, 0, sizeof(deg));
memset(used, 0, sizeof(used));
cnt = 1;
for(int u=1, v, w;u<=n;u++)
for(int i=1;i<=2;i++)
{
scanf("%d %d", &v, &w);
addedge(u, v+n, w);
addedge(v+n, u, w);
deg[u]++,   deg[v+n]++;
}
long long ans = 1;
queue<int> que;
for(int v=n+1;v<=n+n;v++)
if(deg[v] == 1)
que.push(v);
while(!que.empty())///对所有度为1的点进行拓扑排序,并去掉度为1节点
{
int v = que.front();
que.pop();
used[v] = 1;///标记度为1的节点
for(int i=head[v];i;i=e[i].nxt)
{
if(e[i].mrk)    continue;
e[i].mrk = e[i^1].mrk = 1;
used[ e[i].to ] = 1;///因为该节点与度为1的节点相连,所以也要去掉
(ans *= e[i].w) %= mod;
for(int j=head[ e[i].to ];j;j=e[j].nxt)///将于这个点相连的所有边去掉,判断去掉便后,剩余节点的度是否为1,如果为1也要加入队列中
{
e[j].mrk = e[j^1].mrk = 1;
deg[e[j].to]--;
if(deg[ e[j].to ] == 1) que.push(e[j].to);
}
}
}
//cout<<"ans: "<<ans<<endl;
for(int u=1;u<=n;u++)
{
if(used[u]) continue;
part[0] = part[1] = 1;
dfs(u, 0);///调用dfs计算剩余的完美匹配
(ans *= (part[0]+part[1]) % mod) %= mod;
}
printf("%lld\n", ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: