联合权值II link【STL运用】

tonyfang posted @ 2015年9月04日 17:32 in 随笔 with tags c++ OI , 484 阅读

【问题描述】
无向连通图G n 个点,m 条边。点从1 ~ n编号,编号为i 的点权值为$W_i$ 。
每条边长度都为1。对于图G 上的三元组 (u,v,w) ,如果$(u,w,v)$是 $(u,v)$
之间的一

条最短路(这里指 wu,v之间均有直接连边),则它将产生$W_u \times W_v$的联合权值。
请问图G 上所有可产生联合权值的三元组中,联合权值最大的是多少?所有
联合权值之和是多少?

【数据范围】

$n,m \leq 30000$

【题解】

发现了各种$O(n^2)$的算法,听说卡得过,然而并卡不过。

发现,只有三元环会出现要减的情况,其他情况和联合权值一模一样。

那就搞呗~怎样判断三元环?枚举两个,判是否直接连通,set套pair维护即可。

后面的话就枚举三元环即可。

 

# include <stdio.h>
# include <algorithm>
# include <vector>
# include <map>
# include <iostream>
using namespace std;
int n,m,w[30010],t; 
int ans1=-1;
long long ans2=0;
vector <int> g[30010];
vector <int> f[30010];
map < pair<int,int> , bool> s;
inline bool cmp(int a,int b) {
	return w[a]>w[b];
}
int main() {
	freopen("link.in","r",stdin);
	freopen("link.out","w",stdout);
	scanf("%d%d%d",&n,&m,&t);
	for (int i=1,u,v;i<=m;++i) {
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
		s[make_pair(u,v)]=1;
		s[make_pair(v,u)]=1;
	}
	for (int i=1;i<=n;++i) scanf("%d",&w[i]);
	for (int i=1;i<=n;++i) {
		sort(g[i].begin(),g[i].end(),cmp);
		int sizes=g[i].size(),_size=sizes;
		for (int j=0;j<sizes;++j) {
			int k=j+1;
			for (;k<sizes;++k) 
				if (s[make_pair(g[i][j],g[i][k])]==0) break;
			if(k!=sizes) {
				sizes=k;
				ans1=max(ans1,w[g[i][j]]*w[g[i][k]]);
			}
		}
		long long _0=0;
		for (int j=0;j<_size;++j) {
			ans2+=_0*1LL*w[g[i][j]];
			_0+=1LL*w[g[i][j]];
		}
	}
	for (int i=1;i<=n;++i) {
		int sizes=g[i].size();
		for (int j=0;j<sizes;++j)
			if(g[g[i][j]].size()>g[i].size() || (g[g[i][j]].size()==g[i].size() && g[i][j]>i)) {
				f[i].push_back(g[i][j]);
			}
	}
	for (int i=1;i<=n;++i) {
		int sizes=f[i].size();
		for (int j=0;j<sizes;++j) {
			int x=f[i][j],xsizes=f[x].size();
			for (int k=0;k<xsizes;++k)
				if(s[make_pair(i,f[x][k])])
					ans2-=1LL*(w[i]*w[f[x][k]]+w[f[x][k]]*w[x]+w[x]*w[i]);
		}
	}
	if (t!=2) printf("%d\n",ans1); else printf("0\n");
	if (t!=1) cout<<ans2*2<<endl; else printf("0\n");
	return 0;
}
 

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter