您的位置:首页 > 其它

[USACO08OCT]Watering Hole

2016-10-07 11:02 344 查看
一眼看上去是最小生成树

然后发现有打井考虑dp

然后发现好像不能dp

然后发现好像能最小生成树

然后我选择gg

建一个虚拟点 向每个边连一条边权为接水费用的边

引自某题解:

如果去掉加上的这个点,求出最小生成树的图会变成一个个连通分量,而每个连通分量中都必然存在一个打了井的点,也就是说,这些互不相连连通分量之间可以看成是用打井连通的,使该图成为一个连通的图。当你选择在一个点打井时,可以看做你将该点与别的打井了的点连通了,这两个连通分量通过打井连接在了一起,因此可以新建一个点n+1,到原图中每个点的距离等于在该点打井的费用,再求最小生成树。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#define debug(x) cerr<<#x<<"="<<x<<endl
using namespace std;
typedef pair<int,int> pii;
const int INF = 0x7f7f7f7f;
inline int init()
{
int now=0,ju=1;char c;bool flag=false;
while(1)
{
c=getchar();
if(ju=='-')ju=-1;
else if(c>='0'&&c<='9')
{
now=now*10+c-'0';
flag=true;
}
else if(flag)return now*ju;
}
}
struct edge
{
int from,to,val,pre;
}Edge[500001];
int head[301],dis[301];
bool vis[302];
int n,m,cnt=0;
inline void addedge(int from,int to,int val)
{
++cnt;
Edge[cnt]=((edge){from,to,val,head[from]});
head[from]=cnt;
}
int ans=0;
void prim()
{
priority_queue<pii,vector<pii>,greater<pii> > q;
while(!q.empty())q.pop();
for(int i=0;i<=n;i++)
{
dis[i]=INF;
}
pii now,o;
dis[1]=0;q.push(make_pair(dis[1],1));
while(!q.empty())
{
now=q.top();q.pop();
if(vis[now.second])continue;
vis[now.second]=true;
ans+=dis[now.second];
for(int j=head[now.second];j;j=Edge[j].pre)
{
if(!vis[Edge[j].to]&&dis[Edge[j].to]>Edge[j].val)
{
dis[Edge[j].to]=Edge[j].val;
q.push(make_pair(dis[Edge[j].to],Edge[j].to));
}
}
}
}
int main()
{
int a,b;
n=init();
for(int i=1;i<=n;i++)
{
a=init();
addedge(0,i,a);
addedge(i,0,a);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a=init();
if(a==0)continue;
else
{
addedge(i,j,a);
addedge(j,i,a);
}
}
}
prim();
printf("%d\n",ans);
return 0;
}
/*
srO xudyh davidlee1999WTK linkct1999 zlser Orz
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: