1. 程式人生 > >wustoj2230 Cheap deliveries(dijkstra(heap優化) + 狀態壓縮 + dp)

wustoj2230 Cheap deliveries(dijkstra(heap優化) + 狀態壓縮 + dp)

題目:

2230: Cheap deliveries

Time Limit: 2 Sec  Memory Limit: 64 MB   64bit IO Format: %lld
Submitted: 40  Accepted: 16
[Submit][Status][Web Board]

Description

        Abu runs a delivery service where he deliver items from one city to another. As with any business, Abu wants to decrease his cost as much as possible. The further he travel, the more fuel he will use.

        In any particular day, Abu have k items to deliver. Each item needs to be delivered from a start city to a destination city. Each city is represented by an integer. Because of his business policies, he can only deliver one item at a time. However, he can deliver the items in any order that he wants, as long as he deliver all of them. So, everyday he starts at an item's start city and deliver the item to its destination city. Then, he goes to the next items's start city and deliver the item to the its destination city. And, he does this until he does not have any item left to deliver.

        From experimentation, Abu notices that the distance he travels change if he change the order of his delivery. He thought, he can save a lot of money if he knows the best delivery order. He knows that you are very good at solving this kind of problem. So he wants you to solve it for him. Given a list of cities, a list of roads between the cities (and the road's length), and a description of deliveries he must do, determine what is the minimum total travel distance, given that he execute his delivery in the most efficient order.

        Every road is bidirectional and there can be more than one road between two cities. Abu can use any road as many time as he wants.

Input

        The first line consists of two integer n, m, k (2 ≤ n, m ≤ 104), (1 ≤ k ≤ 18) which is the number of cities, the number of roads and the number of items respectively.

        The next m line each consist of 3 integers, ui, vi, li (1 ≤ ui, vi ≤ 10^4), (1 ≤ li ≤ 10^6), which denotes that a road exists from city ui to vi with length li.

        The next k line each consist of 2 integers, fi, di (1 ≤ fi, di ≤ 10^4) which denotes that the ith item is from city fi and its destination is city di.

Output

A single integer, which is the minimum total travel distance given that Abu deliver all items optimally, or -1 if its is impossible for him to deliver all items.

Sample Output 1:

12

Sample Input 

5 5 3
1 2 1
2 3 2
3 4 3
4 5 4
5 2 4
2 3
1 2
5 3

Sample Output

12

HINT

        In the first example, Abu can start from city 5, and deliver the third item, so he move to city 3, travelling a total distance of 6 by going through city 2, then he goes to city 1, travelling a distance of 3 through city 2, and then he deliver the first item to city 2 and then deliver the second item to city 3. The total travel distance is 12.

        In the second example, city 1, 2 and 4 is disconnected from city 3 and 5, therefore it is impossible for Abu to deliver all item.

題意:

有n個城市,m條路,要求走過k對節點,且每次只能從一對節點的頭走向尾,使路徑最小。如果不能走完k對節點輸出-1.

思路:

採取的做法是狀態壓縮,首先用dijkstra+heap把k對節點的頭指向所有其他節點(包括本身的尾)的最短路徑求出來,然後通過將該次是否選取該節點狀態壓縮成0,1.通過dp求解。

AC程式碼:

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e4 + 7;
const ll inf = 0x3f3f3f3f;
const ll INF = 1e18;
int n,m,k;
vector<pair<int,int> > mp[N];
ll dis[N];
bool vis[N];
priority_queue<pair<ll,ll> > Q;
void dij(ll &s)//dijkstra+heap
{
    int now,nxt;

    for(int i=1;i<=n;++i){
        dis[i]=INF;
        vis[i]=false;
    }
    while(!Q.empty())   Q.pop();
    Q.push(make_pair(0,s)),dis[s]=0;
    while(!Q.empty()){
        now=Q.top().second;
        Q.pop();
        if(vis[now]==true)  continue;
        vis[now]=true;
        for(int i=0;i<mp[now].size();++i){
            nxt=mp[now][i].first;
            if(!vis[nxt]&&dis[nxt]>dis[now]+mp[now][i].second){
                dis[nxt]=dis[now]+mp[now][i].second;
                Q.push(make_pair(-dis[nxt],nxt));
            }
        }
    }
}

const int P = 270000;
ll d[20][20],dp[P][18];
pair<ll,ll> pi[N];

int main()
{
    int f,t,l;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        for(int i=1;i<=n;++i)
            mp[i].clear();
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&f,&t,&l);
            mp[f].push_back(make_pair(t,l));
            mp[t].push_back(make_pair(f,l));
        }
        for(int i=1;i<=k;++i)
            scanf("%d%d",&pi[i].first,&pi[i].second);
        for(int i = 0;i < 20;++i)
            for(int j = 0;j < 20;++j)
                d[i][j] = INF;
        for(int i = 1;i <= k;++i){
            dij(pi[i].first);
            for(int j = 1;j <= k;++j)
                d[i][j]=dis[pi[j].second];
        }
        for(int i=0;i<(1<<k);++i)
            for(int j=0;j<=k;++j)
                dp[i][j]=INF;
        for(int i = 0;i < k;++i) dp[1 << i][i] = d[i + 1][i + 1];//每種狀態的初始值是該對節點頭到尾的最短路
        ll ans = inf;
        for(int i = 1;i < (1 << k);++i){//狀態壓縮
            for(int j = 0;j < k;++j){
                if(!(i & (1 << j))) continue;
                for(int l = 0;l < k;++l){
                    if(i & (1 << l)) continue;
                    dp[i|(1 << l)][l]=min(dp[i|(1 << l)][l],dp[i][j] + d[j + 1][l + 1] + d[l + 1][l  + 1]);
                }
                if(i + 1 == (1 << k)) ans = min(ans,dp[i][j]);
            }
        }
        printf("%lld\n",ans == inf ? -1 : ans);
    }
    return 0;
}