链接: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 }