bzoj1003

这道题数据范围很小。

用f[i]表示前i天的最小代价,那么f[i]=min{f[j]+cost(j+1,i)+k}

cost表示从j+1天到第i天找一条 唯一的 最短路径  的长度

#include<cstdio>
#include<cstdlib>
#include<cstring>
int n,m,k,e;    
int first[25];
struct mod{int x,y,z,next;};
mod q[1005];
bool can[25][105];
int t[105];
bool v[105];
int f[105];
int s[105];
int len=0;
void ins(int x,int y,int z)
{
 len++;
 q[len].x=x;
 q[len].y=y;
 q[len].z=z;
 q[len].next=first[x];
 first[x]=len;
}
int mymin(int u1,int u2)
{
 if (u1<u2)return u1;
 return u2;
}
int cost(int stday,int edday)
{
    int st=1,ed=2;
    memset(v,false,sizeof(v));
    v[1]=true;
    for (int i=2;i<=m;i++)
    s[i]=999999999;
    s[1]=0;
    t[1]=1;
    while(st!=ed)
    {
     int x=t[st];
     for (int i=first[x];i!=0;i=q[i].next)
     {
      int y=q[i].y;
      bool tf=true;
      for (int j=stday;j<=edday;j++)
      {
       if (can[y][j]==false)
       {tf=false;break;}    
      }
      if (tf==false)continue;
      if (s[x]+q[i].z<s[y])
      {
       s[y]=s[x]+q[i].z;
       if (v[y]==false)
       {
        v[y]=true;
        t[ed]=y;
        ed++;
        if (ed>m)ed=1;
       }
      }
     }
     v[x]=false;
     st++;
     if (st>m)st=1;
    }
    if (s[m]>999999998)
    return -1;
    else
    return (edday-stday+1)*s[m];
}
int main()
{
 scanf("%d%d%d%d",&n,&m,&k,&e);
 for (int i=1;i<=e;i++)
 {
  int x,y,z;
  scanf("%d%d%d",&x,&y,&z);
  ins(x,y,z);
  ins(y,x,z);   
 }
 memset(can,true,sizeof(can));
 int D;
 scanf("%d",&D);
 for (int i=1;i<=D;i++)
 {
  int p,a,b;
  scanf("%d%d%d",&p,&a,&b);
  for (int j=a;j<=b;j++)
   can[p][j]=false;
 }
 for (int i=1;i<=n;i++)
 {
  int soy=cost(1,i);
  if (soy!=-1)
  f[i]=soy;
  else
  f[i]=999999999;
  for (int j=1;j<i;j++)
  {
   int soy=cost(j+1,i);
   if (soy==-1)continue;
   f[i]=mymin(f[i],f[j]+soy+k);
  }
 }
 printf("%d\n",f[n]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值