[USACO08OCT]Watering Hole

来源:互联网 发布:淘宝客订单一直失效 编辑:程序博客网 时间:2024/04/30 20:37

一眼看上去是最小生成树

然后发现有打井考虑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 */  


0 0
原创粉丝点击