CF 360E Levko and Game——贪心

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

官方题解与证明:http://codeforces.com/blog/entry/9529

一条可以调整的边的边权要么是 l [ i ] 要么是 r[ i ] 。

先把所有可调整边设成 r[ i ] ,然后看看有没有一条可调整的边 (x,y)满足 dis1[x]<=dis2[x] 且其边权还是 r[ i ];如果有,就把它改成 l [ i ]。

改完一条边之后就再做一遍 dij( ) ,然后再改;直到没有可改的边。

其实每次可以不止改一条边,可以把能改的边都改了。因为据证明,一条边 (x,y) 如果 dis1[x]<=dis2[x] ,不会在之后某次修改别的边的时候变成 dis1[x]>dis2[x] 了;所以一旦能改,就一直能改,所以一次改很多能改的边也是可以的。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int N=1e4+5,M=105;
int n,m,t,hd[N],xnt,bh[M],l[M],r[M],s1,s2,F;
ll dis1[N],dis2[N];bool vis[N],ans[M];
priority_queue<pair<ll,int> > q;
struct Ed{
  int x,to,nxt,w;
  Ed(int f=0,int a=0,int b=0,int c=0):x(f),to(a),nxt(b),w(c) {}
}ed[N+M];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
void add(int x,int y,int z){ed[++xnt]=Ed(x,y,hd[x],z);hd[x]=xnt;}
void dj()
{
  memset(dis1,0x3f,sizeof dis1);dis1[s1]=0;
  memset(vis,0,sizeof vis);
  q.push(make_pair(0,s1));
  while(q.size())
    {
      int k=q.top().second;q.pop();
      if(vis[k])continue;vis[k]=1;
      for(int i=hd[k],v;i;i=ed[i].nxt)
    if(dis1[v=ed[i].to]>dis1[k]+ed[i].w)
      dis1[v]=dis1[k]+ed[i].w,q.push(make_pair(-dis1[v],v));
    }
  memset(dis2,0x3f,sizeof dis2);dis2[s2]=0;
  memset(vis,0,sizeof vis);
  q.push(make_pair(0,s2));
  while(q.size())
    {
      int k=q.top().second;q.pop();
      if(vis[k])continue;vis[k]=1;
      for(int i=hd[k],v;i;i=ed[i].nxt)
    if(dis2[v=ed[i].to]>dis2[k]+ed[i].w)
      dis2[v]=dis2[k]+ed[i].w,q.push(make_pair(-dis2[v],v));
    }
}
int main()
{
  n=rdn();m=rdn();t=rdn();
  s1=rdn();s2=rdn();F=rdn();
  for(int i=1,u,v,z;i<=m;i++)
    u=rdn(),v=rdn(),z=rdn(),add(u,v,z);
  for(int i=1,u,v;i<=t;i++)
    {
      u=rdn();v=rdn();l[i]=rdn();r[i]=rdn();
      add(u,v,r[i]); bh[i]=xnt;
    }
  bool flag;
  while(1)
    {
      dj();flag=0;
      for(int i=1,d;i<=t;i++)
    {
      d=bh[i];
      if(ed[d].w==l[i]||dis1[ed[d].x]>dis2[ed[d].x])continue;
      ed[d].w=l[i];ans[i]=1;flag=1;
    }
      if(!flag)break;
    }
  dj();
  if(dis1[F]>dis2[F]){puts("LOSE");return 0;}
  if(dis1[F]==dis2[F])puts("DRAW"); else puts("WIN");
  for(int i=1;i<=t;i++)printf("%d ",ans[i]?l[i]:r[i]);puts("");
  return 0;
}

 

转载于:https://www.cnblogs.com/Narh/p/10135605.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值