题解 P5096 [USACO04OPEN]Cave Cows 1

题目传送门

更好的阅读体验

这题给的数据范围也太弱了吧,为啥 k 给得像状压一样……

题意简述

  • \(n\) 个点 \(m\) 条边的无向图,边有边权,只有当体积小于边权时才能通过。

  • \(k\) 个特殊点上放有食物,吃掉可以使体积加一(经过该点时可以选择不吃)。

  • 初始时体积为 \(0\) ,要求从 \(1\) 号点出发,最后回到 \(1\) 号点,可以重复经过一条边。求最多能吃掉多少食物。

  • \(n \leq 100\)\(m \leq 1000\)\(k \leq 14\)

题目分析

\(w(x,y)\) 表示能从 \(x\) 走到 \(y\) 的最大体积。

由于边可以重复经过,事实上每一个特殊点可以独立考虑

也就是说,贝茜的路线一定可以变为:从 \(1\) 号点出发,到达某个特殊点并吃掉食物,再回到 \(1\) 号点,并将这个过程重复 \(ans\) 次。

理由很简单。假设贝茜走到了特殊点 \(x\) 吃掉食物后体积为 \(p\),又走到特殊点 \(y\) 吃掉食物,那么有 \(w(x,y) \geq p, w(y,1)\geq p+1\)(否则就再也走不回 \(1\) 号点了)。

因此 \(w(x,1) \geq p\),将 \(x \rightarrow y\) 变为 \(x \rightarrow 1 \rightarrow y\) 是合法的。

那么接下来的事情就是算出 \(w(1,t)\),然后每一次贪心选取合法且 \(w(1,t)\) 最小的特殊点吃掉。这一步的排序需要 \(O(k\log k)\) 的时间复杂度。

考虑对每个点 \(t\) 计算 \(w(1,t)\),显然这样的路径一定在最大生成树上,建出树 dfs 一次即可。这一步最小生成树视实现需要 \(O(m \log m)\)\(O(m \log n)\) 的时间复杂度。

总时间复杂度 \(O(k \log k+m \log m)\)\(O(k \log k+m \log n)\),可以非常非常轻松地通过本题。

直接最优解……

代码

#include<bits/stdc++.h>
using namespace std;
const int N=110,M=1100;
struct nod{
	int to,nxt,w;
}e[N*2];
int head[N],cnt;
void add(int u,int v,int w){
	e[++cnt].to=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
int n,m,k;
int p[15],q[15];
int dis[110];

struct abc{
	int u,v,w;
}edg[M*2];
bool operator <(abc x,abc y){
	return x.w>y.w;
}

int fa[N];
int getf(int x){
	if(x==fa[x]) return x;
	return fa[x]=getf(fa[x]);
}
bool merge(int x,int y){
	int fx=getf(x),fy=getf(y);
	if(fx==fy) return 0;
	fa[fx]=fy;
	return 1;
}

void dfs(int u,int fa,int mn){
	dis[u]=mn;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u,min(mn,e[i].w));
	}
}

int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++) scanf("%d",&p[i]);
	for(int i=1;i<=m;i++) scanf("%d%d%d",&edg[i].u,&edg[i].v,&edg[i].w);
	sort(edg+1,edg+m+1);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++){
		int u=edg[i].u,v=edg[i].v;
		if(merge(u,v)) add(u,v,edg[i].w),add(v,u,edg[i].w);
	}
	//最大生成树 
	dfs(1,0,1e9);
	for(int i=1;i<=k;i++) q[i]=dis[p[i]]-1;
	sort(q+1,q+k+1);
	int nw=0,ans=0;//现在的体积 / 答案 
	for(int i=1;i<=k;i++)
		if(nw<=q[i]) nw++,ans++;//贪心 
	cout<<ans;
}
posted @ 2021-06-01 17:09  苹果蓝17  阅读(51)  评论(0编辑  收藏  举报