Matching In Multiplication
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.![](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.
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
12
2 1 1 4
1 4 2 3
Sample Output
16Source
2017 Multi-University Training Contest - Team 4
题意:给出两个顶点集合,每个顶点集合的大小为n,输入v1,w1,v2,w2,表示集合U中的i顶点与集合V中的v1,v2顶点相连,且边的权值为w1,w2。求两个集合的所有完美匹配的权值之和。一个完美匹配的权值为该匹配所有边的权值相乘,且数据保证至少存在一个完美匹配。
题解:首先利用拓扑处理 V 中所有度数为 1 的点,及通过删边操作成为度数为 1 的点。这些点对最终 ans 的贡献为 唯一对应边的权值×唯一对应边的权值
在处理完成后,图中所有未匹配的 U 集合点与 V 集合点个数相同(由于题意指明至少存在一个完备匹配),记作 m 个点。则 U 集合的度数和为 2m,相应的,V 集合的度数和也为 2m(由于U中剩余点每点必然存在两条边,且对应连接到剩余的 V 集合点上)。由于未匹配的 V 集合点已经不存在度数为 1 的情况(已通过拓扑删除),要使得点度合法,则每个点的度数一定也为 2 。故剩余的每个连通块一定成环。间隔取边权,每个连通块的完美匹配权值为part[0]
part[1]
。则该连通块对ans的贡献为×(par
t0+part1)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<math.h>
#include<queue>
#define INF 1e9
#define ll long long
#define maxn 300005
using namespace std;
ll mod=998244353;
struct node
{
int t;
ll v;
};
vector<node>g[maxn*2];
int in[maxn*2];
int vis[maxn*2];
ll ans;
int n;
void top()
{
queue<int>q;
for(int i=n+1;i<=2*n;i++)
if(in[i]==1)
{
q.push(i);
vis[i]=1;
}
while(!q.empty())
{
int e=q.front();
q.pop();
for(int i=0;i<g[e].size();i++)
{
node a=g[e][i];
if(vis[a.t]==1) continue;
in[a.t]--;
if(in[a.t]==1)
{
vis[a.t]=1;
q.push(a.t);
if(a.t<=n)
{
ans*=(a.v%mod);
ans%=mod;
}
}
}
}
}
ll s1;
int tim;
void dfs(int v,ll sum)
{
vis[v]=1;
int flag=0;
for(int i=0;i<g[v].size();i++)
{
node a=g[v][i];
if(vis[a.t]==1) continue;
flag=1;
if(a.t>n)
dfs(a.t,(sum*a.v)%mod);
else dfs(a.t,sum);
if(tim<=1) vis[a.t]=0;
}
if(flag==0)
{
s1+=sum;
s1%=mod;
tim++;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<=2*n;i++)
g[i].clear();
memset(in,0,sizeof(in));
memset(vis,0,sizeof(vis));
ans=1;
for(int i=1;i<=n;i++)
{
int x1,y1;ll x2,y2;
scanf("%d%lld%d%lld",&x1,&x2,&y1,&y2);
x1+=n;
y1+=n;
node e;
e.t=x1;e.v=x2;
g[i].push_back(e);
e.t=y1;e.v=y2;
g[i].push_back(e);
e.t=i;e.v=x2;
g[x1].push_back(e);
e.v=y2;
g[y1].push_back(e);
in[x1]++;in[y1]++;
in[i]+=2;
}
top();
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
s1=0;
tim=0;
dfs(i,1);
ans*=s1;
ans%=mod;
}
}
cout<<ans<<endl;
}
return 0;
}