赞
踩
题意:n个三元组(c1,v,c2). 可以把(c1,v,c2) 变为(c2,v,c1).
若c2[i]==c1[i+1] 则可以把i放在j的左边.
从n个三元组中选出若干个排成一个序列的价值为:所选的v之和.
n<=100. 1<=c<=4. 问最大价值为多少?
由于三元组可以翻转.以三元组为顶点建图没有意义.
以颜色为顶点.若存在三元组(c1,v,c2) 则在(c1,c2)连接一条价值为v的无向边.
建完图后.该图中任意一条路径都表示一个序列.并且每条边都只能使用一次.方向是任意的.
因为只有4种颜色 所以奇数度的个数为0,2,4.
前两种可以直接跑出欧拉路径.权值为最大.(注意是否联通)
并查集维护该联通分量所有边权和.处理前两种情况
4个顶点都为奇数度.那么至少有一条边不会被选上.
并且删除这条边后,这条边所在联通分量中剩下的边都能选上.
注意删除边后,可能会导致不连通(不能用并查集直接维护).此时暴力跑欧拉路径即可.
- #include <bits/stdc++.h>
- using namespace std;
- const int N=2e2+5,M=11;
- int n,val,c1[N],c2[N],v[N],deg[M],ban[N];
- int fa[M],sum[M];
- bool vis[N],mk[N];
- int find(int x){
- return fa[x]==x?x:fa[x]=find(fa[x]);
- }
- void join(int u,int v,int w){
- int x=find(u),y=find(v);
- if(x==y){
- sum[x]+=w;
- return;
- }
- fa[y]=x;
- sum[x]+=sum[y]+w;
- sum[y]=0;
- }
- void dfs(int u){
- vis[u]=true;
- for(int j=1;j<=n;j++){
- if(ban[j]==true|| mk[j]) continue;
- if(c1[j]!=u&&c2[j]!=u) continue;
- mk[j]=true;
- val+=v[j];
- dfs(c1[j]==u?c2[j]:c1[j]);
- }
- }
- int main(){
- ios::sync_with_stdio(false);cin.tie(0);
- cin>>n;
- for(int i=1;i<M;i++) fa[i]=i,sum[i]=0;
- for(int i=1;i<=n;i++){
- cin>>c1[i]>>v[i]>>c2[i];
- deg[c1[i]]++;
- deg[c2[i]]++;
- join(c1[i],c2[i],v[i]);
-
- }
- int nn=4,res=0;
- for(int i=1;i<=nn;i++){
- if(fa[i]!=i) continue;
- int odd=0;
- for(int j=1;j<=nn;j++) if(find(i)==find(j)&°[j]%2) odd++;
- if(odd!=4){
- res=max(res,sum[i]);
- continue;
- }
- for(int j=1;j<=n;j++){
- if(c1[j]==c2[j]) continue;
- memset(mk,0,sizeof(mk));
- memset(vis,0,sizeof(vis));
- ban[j]=true;
- for(int k=1;k<=nn;k++)
- if(k!=c1[j]&&k!=c2[j]){
- val=0;
- dfs(k);
- res=max(val,res);
- break;
- }
- for(int k=1;k<=nn;k++)
- if(!vis[k]){
- val=0,dfs(k);
- res=max(val,res);
- }
- ban[j]=false;
- }
- }
- cout<<res<<'\n';
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。