2017 Multi-University Training Contest

链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1007&cid=762

题意:给定一个二分图,由U、V两部分组成,两部分大小相同,且U中每个点都连向V中的两个点,每个完美匹配的权定义为匹配中的边乘积,求所有完美匹配的权之和。

分析:考虑V中的点,因为题目说了至少有一个完美匹配,所有V中度最少的点至少有一条边,最多两条,如果是一条,它只有一种连法,把对应U中的点删掉,重复以上步骤,最少的那个有两条,那么V中每个点都连两条,整个图由若干个环组成,每个环对应两个匹配,然后乘法一下就得到答案了。。图论的题不打模板就写得很啰嗦。。

  1 #include<iostream>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<vector>
  5 #include<cstring>
  6 using namespace std;
  7 typedef long long ll;
  8 const int maxn=3e5+5,mod=998244353;
  9 struct Vertex{
 10     int c,order;
 11     Vertex(int c,int order){
 12         this->c=c;this->order=order;
 13     }
 14 };
 15 bool operator<(Vertex a,Vertex b){
 16     return a.c>b.c;
 17 }
 18 priority_queue<Vertex> q;
 19 struct Edge{
 20     int s,t,w;
 21     Edge(int s,int t,int w){
 22         this->s=s;this->t=t;this->w=w;
 23     }
 24     Edge(){}
 25 };
 26 bool Is_delete[maxn*2];
 27 vector<Edge>edge;
 28 vector<int> u[maxn],v[maxn];
 29 int coun[maxn],n;
 30 void AddEdge(int s,int t,int w){
 31     u[s].push_back(edge.size());
 32     v[t].push_back(edge.size());
 33     edge.push_back(Edge(s,t,w));
 34 }
 35 ll product=1,ans=1;
 36 void init(){
 37     while(!q.empty())q.pop();
 38     edge.clear();
 39     for(int i=1;i<=n;i++){
 40         u[i].clear();v[i].clear();
 41     }
 42     memset(Is_delete,0,sizeof(Is_delete));
 43     product=1;ans=1;
 44 }
 45 void solve(){
 46     int countc=0;
 47     for(int i=1;i<=n;i++){
 48         q.push(Vertex(v[i].size(),i));
 49         coun[i]=v[i].size();
 50     }
 51     while(1){
 52         Vertex h=q.top();
 53         q.pop();
 54         if(h.c==2)break;
 55         for(int i=0;i<v[h.order].size();i++){
 56             if(Is_delete[v[h.order][i]])continue;
 57             Is_delete[v[h.order][i]]=true;
 58             product=(product*edge[v[h.order][i]].w)%mod;
 59             int tt=v[h.order][i];
 60             int s=edge[v[h.order][i]].s;
 61             for(int i=0;i<2;i++){
 62                 if(edge[u[s][i]].t==h.order)continue;
 63                 if(!Is_delete[u[s][i]]){
 64                     h.c=--coun[edge[u[s][i]].t];
 65                     h.order=edge[u[s][i]].t;
 66                     q.push(h);
 67                 }
 68                 Is_delete[u[s][i]]=true;
 69             }
 70             break;
 71         }
 72     }
 73     while(1){
 74         countc++;
 75         int start,s=-1,t;
 76         ll pro=1,ppro=1;
 77         for(int i=0;i<edge.size();i++){
 78             if(!Is_delete[i]){
 79                 s=start=edge[i].s;
 80                 t=edge[i].t;break;
 81             }
 82         }
 83         if(s==-1)break;
 84         while(1){
 85             for(int i=0;i<u[s].size();i++){
 86                 if(!Is_delete[u[s][i]]){
 87                     pro=(pro*edge[u[s][i]].w)%mod;
 88                     t=edge[u[s][i]].t;
 89                     Is_delete[u[s][i]]=true;
 90                     break;
 91                 }
 92             }
 93             for(int i=0;i<v[t].size();i++){
 94                 if(!Is_delete[v[t][i]]){
 95                     s=edge[v[t][i]].s;
 96                     ppro=(ppro*edge[v[t][i]].w)%mod;
 97                     Is_delete[v[t][i]]=true;
 98                     break;
 99                 }
100             }
101             if(s==start)break;
102         }
103         ans=(ans*(ppro+pro))%mod;
104     }
105     ans=(product*ans)%mod;
106 }
107 int main(){
108     //freopen("e:\in.txt","r",stdin);
109     int t,v1,v2,w1,w2;
110     scanf("%d",&t);
111     while(t--){
112         init();
113         scanf("%d",&n);
114         for(int i=1;i<=n;i++){
115             scanf("%d%d%d%d",&v1,&w1,&v2,&w2);
116             AddEdge(i,v1,w1);
117             AddEdge(i,v2,w2);
118         }
119         solve();
120         cout<<ans<<endl;
121     }
122     return 0;
123 }
原文地址:https://www.cnblogs.com/7391-KID/p/7282531.html