您的位置:首页 > 大数据 > 人工智能

HDU 6073 Matching In Multiplication (拓扑+DFS, 2017 Multi-Univ Training Contest 4)

2017-08-04 15:08 603 查看

Problem

In the mathematical discipline of graph theory, a bipartite graph is a graph whose vertices can be divided into two disjoint sets U and V (that is, U and V are each independent sets) such that every edge connects a vertex in U to one in V. Vertex sets U and V are usually called the parts of the graph. Equivalently, a bipartite graph is a graph that does not contain any odd-length cycles. A matching in a graph is a set of edges without common vertices. A perfect matching is a matching that each vertice is covered by an edge in the set.



Little Q misunderstands the definition of bipartite graph, he thinks the size of U is equal to the size of V, and for each vertex p in U, there are exactly two edges from p. Based on such weighted graph, he defines the weight of a perfect matching as the product of all the edges’ weight, and the weight of a graph is the sum of all the perfect matchings’ weight.

Please write a program to compute the weight of a weighted ”bipartite graph” made by Little Q.

Input

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.

In each test case, there is an integer n(1≤n≤300000) in the first line, denoting the size of U. The vertex in U and V are labeled by 1,2,…,n.

For the next n lines, each line contains 4 integers vi,1,wi,1,vi,2,wi,2(1≤vi,j≤n,1≤wi,j≤109), denoting there is an edge between Ui and Vvi,1, weighted wi,1, and there is another edge between Ui and Vvi,2, weighted wi,2.

It is guaranteed that each graph has at least one perfect matchings, and there are at most one edge between every pair of vertex.

Idea

首先利用拓扑处理 V 中所有度数为 1 的点,及通过删边操作成为度数为 1 的点。这些点对最终 ans 的贡献为 唯一对应边的权值×唯一对应边的权值

在处理完成后,图中所有未匹配的 U 集合点与 V 集合点个数相同(由于题意指明至少存在一个完备匹配),记作 m 个点。则 U 集合的度数和为 2m ,相应的, V 集合的度数和也为 2m (由于 U 中剩余点每点必然存在两条边,且对应连接到剩余的 V 集合点上)。由于未匹配的 V 集合点已经不存在度数为 1 的情况(已通过拓扑删除),要使得点度合法,则每个点的度数一定也为 2 。故剩余的每个连通块一定成环。间隔取边权,每个连通块的完备匹配权值为
part[0]
part[1]
。则该连通块对 ans 的贡献为 ×(part0+part1) 。

Code

#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];
long long part[2];
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) {
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())
{
int v = que.front();
que.pop();
used[v] = 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;
(ans *= e[i].w) %= mod;
for(int j=head[ e[i].to ];j;j=e[j].nxt)
{
e[j].mrk = e[j^1].mrk = 1;
deg[e[j].to]--;
if(deg[ e[j].to ] == 1) que.push(e[j].to);
}
}
}

for(int u=1;u<=n;u++)
{
if(used[u]) continue;
part[0] = part[1] = 1;
dfs(u, 0);
(ans *= (part[0]+part[1]) % mod) %= mod;
}
printf("%lld\n", ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐