HDU 6073 Matching In Multiplication(拓扑+思维)

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.




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

1
2
2 1 1 4
1 4 2 3

Sample Output

16

Source

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;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值