Problem Description
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.
![](https://i-blog.csdnimg.cn/blog_migrate/d538268b0a67d2b02fa9553c081a95b8.jpeg)
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.
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.
Output
For each test case, print a single line containing an integer, denoting the weight of the given graph. Since the answer may be very large, please print the answer modulo
998244353
.
Sample Input
1 2 2 1 1 4 1 4 2 3
Sample Output
16
题意:
给出一个二分图的两个顶点集合,每个顶点集合的大小为n,输入v1,w1,v2,w2,表示集合U中的i顶点与集合V中的v1,v2顶点相连,且边的权值为w1,w2。求两个集合的所有完备匹配的权值之和。一个完备匹配的权值为该匹配所有边的权值相乘,且数据保证至少存在一个完美匹配。
思路:
首先如果一个点的度数为1,那么它的匹配方案是固定的,继而我们可以去掉这一对点。通过拓扑我们可以不断去掉所有度数为1的点。
那么剩下的图中左右各有m个点,每个点度数都不小于2,且左边每个点度数都是2,而右侧总度数是2m,因此右侧只能是每个点度数都是2。这说明这个图每个连通块是个环,在环上间隔着取即可,一共两种方案。
时间复杂度O(n)。
//
// main.cpp
// 1007
//
// Created by zc on 2017/8/27.
// Copyright © 2017年 zc. All rights reserved.
//
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
const int N=660000;
const ll MOD=998244353;
int cnt,n,head[N],du[N],v[N];
ll ans,sum,od,db;
struct node
{
int v,next;
ll c;
}e[N*2];
void init()
{
memset(head,-1,sizeof(head));
memset(du,0,sizeof(du));
memset(v,0,sizeof(v));
cnt=0;
}
void add(int u,int v,ll c)
{
e[cnt].v=v;
e[cnt].c=c;
e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int t,int fa,int from)
{
v[u]=1;
for(int i=head[u];i+1;i=e[i].next)
{
int to=e[i].v;
if(!v[to])
{
if(t&1) od=od*e[i].c%MOD;
else db=db*e[i].c%MOD;
dfs(to,t+1,u,from);
}
else if(to!=fa&&to==from)
{
if(t&1) od=od*e[i].c%MOD;
else db=db*e[i].c%MOD;
return ;
}
}
}
int main(int argc, const char * argv[]) {
int T;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int v1,v2;
ll c1,c2;
scanf("%d%lld%d%lld",&v1,&c1,&v2,&c2);
add(i,v1+n,c1);add(v1+n,i,c1);
add(i,v2+n,c2);add(v2+n,i,c2);
du[v2+n]++;du[v1+n]++;
du[i]=2;
}
ans=1;
queue<int>q;
for(int i=n+1;i<=n+n;i++)
if(du[i]==1) q.push(i);
while(!q.empty())
{
int u=q.front();
q.pop();
v[u]=1;
for(int i=head[u];i+1;i=e[i].next)
{
int t=e[i].v;
if(!v[t])
{
du[t]--;
if(t<=n) ans=ans*e[i].c%MOD;
if(du[t]<=1) q.push(t);
}
}
}
for(int i=1;i<=n;i++)
{
if(!v[i])
{
od=1;db=1;
dfs(i,1,-1,i);
ans=ans*((od+db)%MOD)%MOD;
}
}
printf("%lld\n",ans);
}
}