The 37th ACM/ICPC Asia Regional Tianjin Site Online Contest - G Travel

56 篇文章 0 订阅
24 篇文章 0 订阅
 这道题比赛的时候我做了2个多钟头..最后还是没过..各种都觉得和谐...刚才才发现是因为一个分号..在输入里的一个if语句后加了分号..使得这个判断失效了..囧暴了...去掉分号..果断AC...
 首先当然是Floyd了..得到两两间的最短距离...


方法一:  也就是我比赛的时候这么写的...用DP来解旅行商问题...15个城市可以用15位二进制数表示.最大32767...用dp[k][i]表示在k状态下(0~32767)最后到达的是i城市的最大剩余money.. 

Program:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#define ll long long
#define oo 1000000000
#define pi acos(-1)
using namespace std;  
struct node
{
     int t,c,d;
}p[17];
int arc[105][105],n,m,money,goal,dp[70000][17];
void Floyd()
{
     int k,i,j;
     for (k=1;k<=n;k++)
        for (i=1;i<=n;i++)
           for (j=1;j<=n;j++)
              if (arc[i][k]!=-1 && arc[k][j]!=-1)
                if (arc[i][j]==-1 || arc[i][j]>arc[i][k]+arc[k][j])
                   arc[i][j]=arc[i][k]+arc[k][j];
     return;
}
bool EXE_DP()
{
     int i,j,ans,k,h,x,w,data;
     memset(dp,-1,sizeof(dp));
     p[0].t=1; p[0].c=p[0].d=0;
     w=1;
     dp[0][0]=money;
     for (k=1;k<=goal;k++)  
     {  
             h=k;  
             x=1;  
             i=0;   
             while (h)  
             {  
                   i++;  
                   if (h%2)  
                   {  
                          w=k-x;  
                          for (j=0;j<=n;j++)  
                            if (dp[w][j]!=-1 && arc[p[j].t][p[i].t]!=-1)
                              if (dp[w][j]-arc[p[j].t][p[i].t]>=p[i].d)
                              {
                                     data=dp[w][j]-arc[p[j].t][p[i].t]+p[i].c-p[i].d;
                                     if (dp[k][i]==-1 || dp[k][i]<data) dp[k][i]=data;  
                              }
                   }  
                   x*=2;  
                   h/=2;  
             }  
     }       
     for (i=1;i<=n;i++)
        if (arc[p[i].t][1]!=-1 && dp[goal][i]!=-1 && dp[goal][i]>=arc[p[i].t][1]) 
            return true;
     return false;
}
int main()
{  
    // freopen("input.txt","r",stdin);    freopen("output.txt","w",stdout); 
     int t,x,y,h,w;
     scanf("%d",&t);
     while (t--)
     { 
           memset(arc,-1,sizeof(arc));
           scanf("%d%d%d",&n,&m,&money);
           while (m--)
           {
                  scanf("%d%d",&x,&y);
                  scanf("%d",&w);
                  if (arc[y][x]==-1 || w<arc[y][x])
                      arc[x][y]=arc[y][x]=w;
           }
           for (x=1;x<=n;x++) arc[x][x]=0;
           Floyd();
           scanf("%d",&h);
           goal=1;
           for (x=1;x<=h;x++) 
           {
                  scanf("%d%d%d",&p[x].t,&p[x].c,&p[x].d); 
                  goal*=2;
           } 
           n=h;
           goal--;
           if (EXE_DP()) printf("YES\n");
                    else printf("NO\n");
     }
     return 0;
}


方法二: 暴力找答案..这题并不是严格的旅行商问题..因为题目只要求能否找到在一定条件下遍历所有点的任一路径..并不是找最短路径..所以..纯暴力吧~~ 4000MS...

Program:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#define ll long long
#define oo 10000000
#define pi acos(-1)
using namespace std;  
struct node
{
     int t,c,d;
}p[17];
int arc[105][105],n,m,h;
bool used[17];
void Floyd()
{
     int k,i,j;
     for (k=1;k<=n;k++)
        for (i=1;i<=n;i++)
           for (j=1;j<=n;j++) 
                if (arc[i][j]-arc[i][k]>arc[k][j])
                    arc[i][j]=arc[i][k]+arc[k][j];
     return;
} 
bool DFS(int money,int k,int now)
{ 
     if (k==h) 
     {
             if (money>=arc[p[now].t][1]) return true;  
             return false;
     }
     used[now]=true;
     for (int i=1;i<=h;i++)
       if (!used[i] && money-arc[p[now].t][p[i].t]>=p[i].d)
          if (DFS(money-arc[p[now].t][p[i].t]-p[i].d+p[i].c,k+1,i)) return true;
     used[now]=false;
     return false;     
}
int main()
{  
     freopen("input.txt","r",stdin);    freopen("output.txt","w",stdout); 
     int t,x,y,w,money;
     scanf("%d",&t);
     while (t--)
     { 
           scanf("%d%d%d",&n,&m,&money);
           for (y=0;y<=n;y++)
              for (x=0;x<n;x++) 
                 arc[y][x]=arc[x][y]=oo;       
           while (m--)
           {
                  scanf("%d%d%d",&x,&y,&w);
                  if (w<arc[y][x])
                      arc[x][y]=arc[y][x]=w;
           }
           for (x=1;x<=n;x++) arc[x][x]=0; 
           Floyd();       
           scanf("%d",&h);  
           for (x=1;x<=h;x++)  
               scanf("%d%d%d",&p[x].t,&p[x].c,&p[x].d);  
           p[0].t=1;  p[0].c=p[0].d=0; 
           memset(used,false,sizeof(used));
           if (DFS(money,0,0)) printf("YES\n");
                     else    printf("NO\n");
           
     }
     return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值