Acdream 1083 人民城管爱人民

来源:互联网 发布:淘宝店铺收藏图片 编辑:程序博客网 时间:2024/04/25 20:31

很好的dp题目,不过当时比赛的时候太傻逼,都没意识到这是dp题。

以后要养成习惯了,对于一个DAG来说,dp是解决相关问题的很好的工具。

对于一个点u,我们记录它的两种状态dp[u][0]表示从u开始没有破坏路的最短路径,dp[u][1]表示从u开始破坏了一条路径的最短路径。

第一个状态的转移很好解决。

第二个状态的转移一定要注意这是一个博弈的过程,城管也是很有智商的。。。

#include <cstdio>#include <cstring>#include <vector>using namespace std;#define inf 10000000struct edge{    int to;    int cost;};const int maxn = 1e4;vector<edge> g[maxn];bool vis[maxn];int dp[maxn][2];int n,m;void dfs(int s){    if(vis[s]==true)  return;    if(s==n-1)    {        dp[s][0]=dp[s][1]=0;        return;    }    if(g[s].size()==0)    {        dp[s][0]=dp[s][1]=inf;        return;    }    int size=(int)g[s].size();    vis[s]=true;    for(int i=0;i<size;i++)    {        dfs(g[s][i].to);    }    int loc=-1;    dp[s][0]=inf;    for(int i=0;i<size;i++)    {        edge tmp=g[s][i];        if(dp[tmp.to][0]+tmp.cost<dp[s][0])        {            loc=i;            dp[s][0]=dp[tmp.to][0]+tmp.cost;        }    }    if(size==1)    {        dp[s][1]=inf;    }    else    {        dp[s][1]=inf;        int v1=inf,v2=inf;        for(int i=0;i<size;i++)        {            edge tmp=g[s][i];            v1=min(v1,dp[tmp.to][1]+tmp.cost);            if(i!=loc)            {                v2=min(v2,dp[tmp.to][0]+tmp.cost);            }        }        dp[s][1]=max(v1,v2);    }    return;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        for(int i=0;i<n;i++)  g[i].clear();        int from,to,cost;        while(m--)        {            scanf("%d%d%d",&from,&to,&cost);            g[from].push_back((edge){to,cost});        }        memset(vis,false,sizeof(vis));        dfs(0);        /*         for(int i=0;i<n;i++)         {         printf("%d %d\n",dp[i][0],dp[i][1]);         }*/        if(dp[0][1]>=inf)  puts("-1");        else  printf("%d\n",dp[0][1]);    }    return 0;}


0 0