现在的位置: 首页 > 算法 > 正文

zoj2963

2019年08月20日 算法 ⁄ 共 2091字 ⁄ 字号 评论关闭

状态压缩dp这题坑在特判

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
       int id;
       int l;
       friend bool operator<(node a,node b)
       {
              return a.l>b.l;
       } 
};
const int MAX=99999999; 
vector<node>vt[501];
int cost[501];
int mark[501];
int vi[501][501];
int pa[501][501],psp[501][501];
int temp[501]; 
int n;
int dp[140000][20];
int maxn(int a,int b)
{
    return a<b?a:b;
} 
void dij(int x)
{
     priority_queue<node>q;
     pa[x][x]=cost[x];
     node s;
     s.id=x;
     s.l=0;
     node tt;
     q.push(s);
     int count=0;
     while(!q.empty()&&count<n)
     {
                      s=q.top();
                      q.pop();
                      int mi=s.id;
                      if(vi[x][mi])
                      continue;
                      vi[x][mi]=1;//好久没写优先队列dij,只有每次弹出的点才要更新vi[x][mi]=1,因为弹出的点是放入最短集合的.
                      count++;
                      for(int i=0;i<vt[mi].size();i++)
                      {
                              int t=vt[mi][i].id;
                              int le=vt[mi][i].l;
                              if(!vi[x][t]&&pa[x][t]>pa[x][mi]+le+cost[t])
                              {
                                                                          pa[x][t]=pa[x][mi]+le+cost[t];
                                                                          tt.id=t;
                                                                          tt.l=pa[x][t];
                                                                          q.push(tt);
                              }
                      }
     }
}                               
int main()
{
    while(1==scanf("%d",&n))
    {
                            memset(dp,-1,sizeof(dp)); 
                            for(int i=1;i<=n;i++)
                            {
                                    temp[i]=0; 
                                    vt[i].clear(); 
                            for(int j=1;j<=n;j++) 
                            {
                                    pa[i][j]=MAX;
                                    vi[i][j]=0;
                            } 
                            } 
                            for(int i=1;i<=n;i++)
                                    scanf("%d",cost+i);
                            int t;
                            scanf("%d",&t);
                            for(int i=1;i<=t;i++)
                            {
                                    int a;
                                    scanf("%d",&a);
                                    temp[a]=1;
                            } 
                            int m;
                            scanf("%d",&m);
                            for(int i=1;i<=m;i++)
                            {
                                    int a,b,c;
                                    scanf("%d%d%d",&a,&b,&c);
                                    node s;
                                    s.id=b;
                                    s.l=c;
                                    vt[a].push_back(s);
                                    s.id=a;
                                    vt[b].push_back(s);
                            }
                            int st,ed;
                            scanf("%d%d",&st,&ed);
                            int jj=0; 
                            mark[++jj]=st;
                            for(int i=1;i<=n;i++)
                            {
                                    if(i!=st&&i!=ed&&temp[i])
                                    mark[++jj]=i;
                            } 
                            if(st!=ed)
                            mark[++jj]=ed;
                            for(int i=1;i<=jj;i++)
                                    dij(mark[i]);
                            for(int i=1;i<=jj;i++)
                                    for(int j=1;j<=jj;j++)
                                            psp[i][j]=pa[mark[i]][mark[j]];
                            if(t==0||jj==1)
                            {
                                           printf("%d\n",pa[st][ed]);
                                           continue;
                            }
                      /*      printf("%d\n",jj);
                            for(int i=1;i<=jj;i++)
                            for(int j=1;j<=jj;j++)
                            printf("%d %d %d\n",i,j,psp[i][j]);*/
                            dp[1][1]=psp[1][1];
                            for(int i=1;i<(1<<jj);i++)
                            for(int j=1;j<=jj;j++)
                            {
                                    if(dp[i][j]==-1)
                                    continue;
                                    for(int k=1;k<=jj;k++)
                                    if(!(i&(1<<(k-1))))
                                    {
                                                       int z=i|(1<<(k-1));
                                                       if(dp[z][k]==-1||dp[i][j]+psp[j][k]-cost[mark[j]]<dp[z][k])
                                                       dp[z][k]=dp[i][j]+psp[j][k]-cost[mark[j]];
                                    }
                            }
                            if(st!=ed)
                            printf("%d\n",dp[(1<<jj)-1][jj]);
                            else//如果起点终点相同则要令判,枚举所有中间点得出最小值。
                            {
                                int w=((1<<jj)-1);
                                int ans=MAX;
                                for(int i=2;i<=jj;i++)
                                {
                                        ans=maxn(ans,dp[w][i]+psp[i][1]-cost[mark[i]]);
                                }
                                printf("%d\n",ans);
                            }
    }
    return 0;
}

临界,题目可以转化为 一群要到的点(宝藏地)用dijistra求出相互间的最短路,然后一个状态压缩dp求得answer

【上篇】
【下篇】

抱歉!评论已关闭.