CF 360 E Levko and Game —— 贪心+最短路

题目:http://codeforces.com/contest/360/problem/E

首先,每条边不是选 \( l[i] \) 就是选 \( r[i] \);

做法就是先把边权都设成 \( r[i] \),然后做 \( dijkstra \),如果有一条可改的边 \( (a,b) \) 而且 \( dis1[a] < dis2[a] \),那么就改边权为 \( l[i] \);

然后重复这个过程直到无边可改;

因为要考虑平局,所以只要 \( dis1[a] <= dis2[a] \) 就改,这样先让第一个人的路是最优的;

其实也不用一条一条改,一次改所有能改的就行,因为据题解的证明,一次改了一条边后,不会使一个 \( dis1[a] <= dis2[a] \) 的边突然变得 \( dis1[a] > dis2[a] \)

题解的证明...看不动了...感性理解...

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const xn=1e4+105,xm=105;
int n,m,cnt,hd[xn],ct,to[xn],nxt[xn],w[xn],s1,s2,f;
ll dis[2][xn],inf=1e17;
bool vis[xn];
struct E{int u,v,bh,l,r,w;}ed[xm];
struct N{
  ll d; int id;
  N(ll d=0,int i=0):d(d),id(i) {}
  bool operator < (const N &y) const
  {return d>y.d;}
};
priority_queue<N>q;
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return f?ret:-ret;
}
void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; w[ct]=z;}
void dij(int t)
{
  for(int i=1;i<=n;i++)dis[t][i]=inf;
  for(int i=1;i<=n;i++)vis[i]=0;
  int st=(t?s2:s1);
  dis[t][st]=0; q.push(N(0,st));
  while(q.size())
    {
      int x=q.top().id; q.pop();
      if(vis[x])continue; vis[x]=1;
      for(int i=hd[x],u;i;i=nxt[i])
    if(dis[t][u=to[i]]>dis[t][x]+w[i])
      {
        dis[t][u]=dis[t][x]+w[i];
        q.push(N(dis[t][u],u));
      }
    }
}
int main()
{
  n=rd(); m=rd(); cnt=rd();
  s1=rd(); s2=rd(); f=rd();
  for(int i=1,x,y,z;i<=m;i++)x=rd(),y=rd(),z=rd(),add(x,y,z);
  for(int i=1;i<=cnt;i++)
    ed[i].u=rd(),ed[i].v=rd(),ed[i].l=rd(),ed[i].r=rd(),
      ed[i].bh=ct+1,ed[i].w=1,add(ed[i].u,ed[i].v,ed[i].r);
  dij(0); dij(1);
  while(dis[0][f]>=dis[1][f])
    {
      int i;
      for(i=1;i<=cnt;i++)
    if(dis[0][ed[i].u]<=dis[1][ed[i].u]&&ed[i].w)break;
      if(i>cnt)
    {
      if(dis[0][f]>dis[1][f])puts("LOSE"); 
      else 
        {
          puts("DRAW");
          for(int j=1;j<=cnt;j++)printf("%d ",ed[j].w?ed[j].r:ed[j].l);
          puts("");
        }
      return 0;
    }
      ed[i].w=0; w[ed[i].bh]=ed[i].l; dij(0); dij(1);
    }
  puts("WIN");
  for(int j=1;j<=cnt;j++)printf("%d ",ed[j].w?ed[j].r:ed[j].l);
  puts("");
  return 0;
}

 

posted @ 2018-12-18 10:27  Zinn  阅读(232)  评论(0编辑  收藏  举报