Matching In Multiplication HDU - 6073 topsort+

https://vjudge.net/contest/176221#problem/G

题意:给出一个二分图的两个顶点集合,每个顶点集合的大小为n,输入v1,w1,v2,w2,表示集合U中的i顶点与集合V中的v1,v2顶点相连,且边的权值为w1,w2。求两个集合的所有完备匹配的权值之和。一个完备匹配的权值为该匹配所有边的权值相乘,且数据保证至少存在一个完美匹配。

#include<algorithm>
#include<vector>
#include<cstring>
#include<string>
#include<iomanip>
#include<cstdio>
#include<stack>
#include<iostream>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
#define sf scanf
#define pf printf
#define mem(a,b) memset(a,b,sizeof(a));
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define bug1 puts("bug1");
#define bug2 puts("bug2");
#define bug3 puts("bug3");
#define N 600010
#define M 1200020
#define mod 998244353
#define ULL unsigned long long
#define LL long long
#define inf 0x3f3f3f3f
//2017年08月05日13:00:00

LL part[2];
int fst[N],du[N],vv[M],vis[N],cost[M],nxt[M],e;
bool use[M];

void add(int u,int v,int w ){
    vv[e]=v;nxt[e]=fst[u];cost[e]=w;fst[u]=e++;
}
void dfs(int u,int flag){
    vis[u]=1;
    for(int i=fst[u];~i;i=nxt[i]){
        int v=vv[i];
        if(use[i])continue;
        part[flag]=(part[flag]*cost[i])%mod;
        use[i^1]=use[i]=true;
        dfs(v,flag^1);
    }
}

int main(){
    int T ;sf("%d",&T);
    while(T--){
        int n;sf("%d",&n);
        mem(fst,-1);e=0;
        mem(du,0);mem(vis,0);mem(use,0);
        rep(i,1,n){
            int v1,w1,v2,w2;sf("%d%d%d%d",&v1,&w1,&v2,&w2);
            add(i,v1+n,w1);add(v1+n,i,w1);
            add(i,v2+n,w2);add(v2+n,i,w2);
            du[v1+n]++;du[v2+n]++;
            du[i]+=2;
        }
        queue<int>q;
        for(int i=n+1;i<=2*n;++i){
            if(du[i]==1){q.push(i);}
        }
        LL ans=1;
        mem(use,false);
        while(!q.empty()) {
            int v=q.front();
            q.pop(),vis[v]=1;
            for(int i=fst[v]; ~i; i=nxt[i]) {
                if(use[i])continue;
                use[i]=use[i^1]=true;
                vis[vv[i]]=1;
                ans=(ans*cost[i])%mod;
                for(int j=fst[vv[i]]; ~j; j=nxt[j]) {
                    use[j]=use[j^1]=true;
                    --du[vv[j]];
                    if(du[vv[j]]==1)
                        q.push(vv[j]);
                }
            }
        }
        for(int i=1;i<=n;++i){
            part[1]=part[0]=1;
            if(!vis[i]){
                dfs(i,0);
                ans=(ans*(part[0]+part[1])%mod)%mod;
            }
        }
        pf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值