absi2011's Blog & Daily Life.

全新的开始       我要省选翻盘       I wanna AK in 高考\化学       自此,生无可恋
[破碎的状态] [-37] 100818 B-分块解法
[破碎的状态] [-36] 641E

[破碎的状态] [-37] 100818 E

absi2011 posted @ Jun 15, 2016 04:56:26 PM in 刷题记录 with tags CF Gym 小高考 dijkstra DP , 539 阅读

感谢@似水流年 翻译

题意:

在一个强联通图上,有n个人要打车,他们都在某点上(2<=n<=15)

允许拼车,但一个车上最多4个人

打一个车的代价是路费+起步价,起步价给定输入,路费即路程的权值和

解法:

先dijkstra那么几次,以初始点和每个目的地为中心dijkstra一发

然后..dp一发..

复杂度[tex]O(4 * 2^n * n^2)[/tex]

代码:

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<time.h>
#include<bitset>
#include<vector>
#include<memory>
#include<utility>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct edge
{
    int y;
    int weight;
    edge * next;
};
edge * li[100005];
edge * new_edge()
{
    static edge a[100005];
    static int top=0;
    return &a[top++];
}
void insert_edge(int x,int y,int z)
{
    edge * t=new_edge();
    t->y=y;
    t->weight=z;
    t->next=li[x];
    li[x]=t;
}
int a[100005];
int dist[100005];
int dis[25][25];
bool visit[100005];
void dijkstra(int num)
{
    priority_queue<pair<int,int> > q;
    memset(dist,-1,sizeof(dist));
    memset(visit,0,sizeof(visit));
    q.push(make_pair(0,num));
    dist[num]=0;
    for (;!q.empty();)
    {
        int x=q.top().second;
        q.pop();
        if (visit[x]) continue;
        visit[x]=true;
        edge * t;
        for (t=li[x];t!=0;t=t->next)
        {
            if ((dist[t->y]==-1)||(dist[t->y]>dist[x]+t->weight))
            {
                dist[t->y]=dist[x]+t->weight;
                q.push(make_pair(-dist[t->y],t->y));
            }
        }
    }
}
int dp[1<<15][5][25];
int main()
{
    #ifdef absi2011
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    #endif
    int n,m;
    scanf("%d%d",&n,&m);
    int i;
    for (i=0;i<m;i++)
    {
        int t;
        scanf("%d",&t);
        int x;
        int y;
        int z;
        scanf("%d%d%d",&x,&y,&z);
        x--;
        y--;
        insert_edge(x,y,z);
        if (t==2) insert_edge(y,x,z);
    }
    int val;
    scanf("%d",&val);
    int num;
    scanf("%d",&num);
    num--;
    int k;
    scanf("%d",&k);
    for (i=0;i<k;i++)
    {
        scanf("%d",&a[i]);
        a[i]--;
    }
    dijkstra(num);
    for (i=0;i<k;i++)
    {
        dis[k][i]=dist[a[i]];
    }
    for (i=0;i<k;i++)
    {
        dijkstra(a[i]);
        int j;
        for (j=0;j<k;j++)
        {
            dis[i][j]=dist[a[j]];
        }
    }
    for (i=0;i<(1<<k);i++)
    {
        int j;
        for (j=0;j<4;j++)
        {
            int l;
            for (l=0;l<=k;l++)
            {
                dp[i][j][l]=99999999;
            }
        }
    }
    for (i=0;i<k;i++)
    {
        dp[1<<i][0][i]=val+dis[k][i];
    }
    for (i=1;i<(1<<k);i++)
    {
        int j;
        for (j=0;j<4;j++)
        {
            int l;
            for (l=0;l<k;l++)
            {
                if (((1<<l)&i)==0) continue;
                int jj;
                for (jj=0;jj<k;jj++)
                {
                    if ((1<<jj)&i) continue;
                    dp[i^(1<<jj)][j+1][jj]=min(dp[i^(1<<jj)][j+1][jj],dp[i][j][l]+dis[l][jj]);
                    dp[i^(1<<jj)][0][jj]=min(dp[i^(1<<jj)][0][jj],dp[i][j][l]+dis[k][jj]+val);
                }
            }
        }
    }
    int min_ans=99999999;
    int t=(1<<k)-1;
    for (i=0;i<4;i++)
    {
        int l;
        for (l=0;l<k;l++)
        {
            min_ans=min(min_ans,dp[t][i][l]);
        }
    }
    printf("%d\n",min_ans);
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter