题意:给出一个二部图,U、V分别是二部图的两个点集,其中,U中每个点会有两条边连到V中两个不同的点。完美匹配定义为:所有点都成功匹配。完美匹配的权值定义为:匹配的边集所有边长度的乘积。图的权值定义为:所有不同方案的完美匹配的权值的和。给出的图满足一定存在完美匹配。
题解:这个题开始拿到不知道如何入手,只知道U中每个点出度都是2,并且U、V都有n个点,那么很显然V、U都有2n的度。考虑匹配:U中每个点有两个度,那么每个点有两种备选方案。V中所有点的度是2n,但是每个点的度可以各不相同,比如说某个点 y 的度是1,设这个边是 z ,那么很显然他必须匹配这一条边,那么这条边对应U中的点假设是x,那么 x 一定要用 z 这个边去匹配 y 这个点。于是x的另外一条边 t 就没用了,我们把他去掉,那么假设 t 连接了 x 和 p ,那么p的度就少了1,如果说此时p的度变成了1,那么好巧,p也只剩下一个救命稻草了,以此类推,我们从度为1的点出发,先找到了一系列 “必须这样匹配“ 的点和边。假设通过上述方法确定了 k 个点的唯一匹配方案,那么现在 U中剩余了n-k个点,V也是,而且U中有2*(n-k)的度,V也是,而且,V中入度为1的点已经全部被摘除,剩下的点入度必然>=2,(n-k)个点,2(n-k)的总度,每个点度>=2,那么说明每个点的度必为2。这就构成了环,而且在一个环中,只有两种方案A,B。答案=ANS1*(A1+B1)*(A2+B2)*……把括号展开的每一项就是所有的完美匹配的权值。
Code:
#include<bits/stdc++.h>
using namespace std;
const int TZY = 998244353;
const int MAX = 300050;
bool vis[MAX*2];
int rd[MAX*2];
long long ans;
struct Edge{
int des,length;
Edge(int des_,int length_):des(des_),length(length_){}
};
vector<Edge> E[MAX*2];
int n;
long long tempAns,tempAns1;
int que[MAX*5];
int l,r;
int cot[MAX*2];
void init(){
for(int i=0;i<MAX*2;i++){
E[i].clear();
}
memset(rd,0,sizeof(rd));
memset(vis,false,sizeof(vis));
memset(cot,0,sizeof(cot));
l=0;
r=0;
ans = 1;
}
void input(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
int v1,w1,v2,w2;
scanf("%d %d %d %d",&v1,&w1,&v2,&w2);
E[i].push_back(Edge(v1+n,w1));
E[v1+n].push_back(Edge(i,w1));
E[i].push_back(Edge(v2+n,w2));
E[v2+n].push_back(Edge(i,w2));
rd[i]+=2;
rd[v1+n]++;
rd[v2+n]++;
}
for (int i=1;i<=2*n;i++){
if (rd[i]==1){
r++;
que[r] = i;
}
}
}
void dfs(int node,int fa,int root,int flag){
vis[node] = true;
for (Edge temp :E[node]){
int v = temp.des;
int length = temp.length;
if (v==fa){
continue;
}
if (!vis[v]||v==root){
if (!flag){
tempAns1*=length;
tempAns1%=TZY;
}else{
tempAns*=length;
tempAns%=TZY;
}
}
if (!vis[v]){
dfs(v,node,root,flag^1);
}
}
}
void work(){
while (l<r){
l++;
int q = que[l];
vis[q] = true;
if (rd[q]==0){
continue;
}
for (Edge temp :E[q]){
int v = temp.des;
int length = temp.length;
rd[v]--;
if (rd[v]==1&&!vis[v]){
r++;
que[r] = v;
if (q>n){
ans*=length;
ans%=TZY;
}
}
}
}
for (int i=1;i<=n;i++){
if (!vis[i]){
tempAns=1LL;
tempAns1=1LL;
dfs(i,0,i,0);
ans*=(tempAns1+tempAns);
ans%=TZY;
}
}
printf("%I64d\n",ans);
}
int main(){
freopen("1007.in","r",stdin);
int t;
scanf("%d",&t);
while (t--){
init();
input();
work();
}
}