SRM579 Div1Medium TravellingPurchasingMan

来源:互联网 发布:头条新闻软件下载 编辑:程序博客网 时间:2024/06/01 23:03

【分析】
看了下范围,1≤p≤min(16,n)还是把这道题卖了。显然是状压dp嘛。
那我们就定义dp[i][j]表示此时在i这个店,已经在j这个集合买了物品,所需要花的最少的时间。
这个dp状态的转移不太好用我最喜欢的记忆化搜索。(不开心)
不过从i店到j店的最短距离还是需要Floyd跑一下的。(TC的范围那么小,不用Floyd真的很浪费啊!)

【代码】

#include <bits/stdc++.h>using namespace std;#define oo 1e9#define M 55int dp[M][1<<16];int dis[M][M];int n,p,m;int ans;struct node{    int l,r,t;}a[M];void chk(int &x,int y){    if(x>y)x=y;}int main(){    scanf("%d %d %d",&n,&p,&m);    for(int i=0;i<p;i++)scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].t);    for(int i=0;i<n;i++){        for(int j=0;j<n;j++){            if(i!=j)dis[i][j]=oo;            else dis[i][j]=0;        }    }    for(int i=1;i<=m;i++){        int x,y,z;        scanf("%d %d %d",&x,&y,&z);        dis[x][y]=dis[y][x]=min(dis[x][y],z);    }    for(int k=0;k<n;k++){        for(int i=0;i<n;i++){            for(int j=0;j<n;j++)chk(dis[i][j],dis[i][k]+dis[k][j]);        }    }    for(int k=0;k<(1<<p);k++){        for(int i=0;i<p;i++)dp[i][k]=oo;    }    for(int i=0;i<p;++i)dp[i][0]=dis[n-1][i];    for(int k=0;k<(1<<p);k++){        int cnt=1+__builtin_popcount(k);        for(int i=0;i<p;i++){            for(int j=0;j<p;j++){                if(k&(1<<j))continue;                if(dp[i][k]+dis[i][j]>a[j].r)continue;                chk(dp[j][k|(1<<j)],a[j].t+max(dp[i][k]+dis[i][j],a[j].l));                ans=max(ans,cnt);            }        }    }    printf("%d\n",ans);    return 0;}
2 0