刷题总结——做运动(NOIP模拟)

题目:

  给定一个无向图,节点数n<=50000,m<=1000000,每条边有两个值t和c,边的长度为t*c···现在要求再t尽量小的情况下,求两节点st的最短距离

题解:

  第一次做的时候想都没有想直接用二分+迪杰斯特拉了···哎连复杂度都算不来了···

  正解应该是将边按t升序排序后跑kruskals····用并差集判st是否连通··一旦联通将t值小于等于目前枚举的t值的边全部加入建图然后跑最短路就可以了···

  其实如果考试时仔细想一想时是可以想到正解的··毕竟如果t要尽量小的话不是二分就是最小生成树了···但并差集判连通性这一点已经很久每用过了··这题算是提了醒吧··

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
priority_queue< pair<long long,int> >que;
const int N=5e5+5;
const int M=1e6+5;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0'; 
  return f;
}
struct node
{
  int x,y,T,C;
  inline friend bool operator < (node a,node b)
  {
    return a.T<b.T;
  }
}edge[M]; 
int Father[N],fst[N],go[M*2],nxt[M*2],n,m,src,des,anst,tot;
long long dis[N],val[M*2];
inline bool comb(int a,int b,int c,int d)
{
  nxt[++tot]=fst[a],fst[a]=tot,go[tot]=b,val[tot]=(long long)c*d;
  nxt[++tot]=fst[b],fst[b]=tot,go[tot]=a,val[tot]=(long long)c*d;
}
inline int get(int a)
{
  if(Father[a]==a)  return a;
  else return Father[a]=get(Father[a]);
}
inline void solve()
{
  for(register int i=1;i<=n;i++)  dis[i]=2e+18;
  dis[src]=0;que.push(make_pair(0,src));
  while(!que.empty())
  {
    int u=que.top().second;que.pop();
    if(u==des)  break; 
    for(register int e=fst[u];e;e=nxt[e])
    {
      int v=go[e];
      if(dis[v]>dis[u]+val[e])
      {
        dis[v]=dis[u]+val[e]; 
        que.push(make_pair(-dis[v],v));
      }
    }
  }
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R();m=R();  
  for(register int i=1;i<=n;i++)  Father[i]=i;
  for(register int i=1;i<=m;i++)  edge[i].x=R(),edge[i].y=R(),edge[i].T=R(),edge[i].C=R();
  src=R();des=R();
  sort(edge+1,edge+m+1);
  for(register int i=1;i<=m;i++)
  {
    int fx=get(edge[i].x),fy=get(edge[i].y);
    Father[fx]=fy;
    if(get(src)==get(des))  
    {
      anst=edge[i].T;
      break;
    }
  }
  cout<<anst<<" ";
  for(register int i=1;i<=m;i++)
  {
    if(edge[i].T>anst)  break;
    comb(edge[i].x,edge[i].y,edge[i].T,edge[i].C);
  }
  solve();cout<<dis[des]<<endl;
  return 0;
}

 

posted @ 2017-10-26 15:54  AseanA  阅读(237)  评论(0编辑  收藏  举报