【多校训练】hdu 6073 Matching In Multiplication. 拓扑+dfs

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(1T15) , denoting the number of test cases.

In each test case, there is an integer  n(1n300000)  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(1vi,jn,1wi,j109) , 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。求两个集合的所有完备匹配的权值之和。一个完备匹配的权值为该匹配所有边的权值相乘,且数据保证至少存在一个完美匹配。


思路:

首先如果一个点的度数为11,那么它的匹配方案是固定的,继而我们可以去掉这一对点。通过拓扑我们可以不断去掉所有度数为11的点。

那么剩下的图中左右各有mm个点,每个点度数都不小于22,且左边每个点度数都是22,而右侧总度数是2m2m,因此右侧只能是每个点度数都是22。这说明这个图每个连通块是个环,在环上间隔着取即可,一共两种方案。

时间复杂度O(n)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);
    }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值