您的位置:首页 > 其它

LightOJ - 1316 A Wedding Party(最短路+状态压缩)

2015-11-10 21:08 330 查看
题目大意:有N个点,M条有向边,S个特殊点。现在要求你从0走到N-1,经过的特殊点的数量最多,且走过的路径最小

解题思路:刚开始开了一个dp
[1 << S]的数组,可想而知,MLE了

后面想想,只需要处理出(开始点,特殊点,终点)这些点之间的距离,再用状态压缩去做就好了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int M = 10010;
const int N = 510;
const int S = (1 << 15) + 10;
const int INF = 0x3f3f3f3f;

struct Edge{
int u, v, dis, next;
Edge() {}
Edge(int u, int v, int dis, int next): u(u), v(v), dis(dis), next(next) {}
}E[M];

struct Node {
int u, dis;
Node() {}
Node(int u, int dis): u(u), dis(dis) {}
bool operator < (const Node &a) const {
return dis > a.dis;
}
};

struct DP{
int pos, statu;
DP() {}
DP(int pos, int statu): pos(pos), statu(statu) {}
};

int head
, dis[20]
, shop[20], dp[20][S];
bool vis
, start_shop;
int n, m, s, cas = 1;

void init() {
memset(head, -1, sizeof(head));

scanf("%d%d%d", &n, &m, &s);
int u, v, dis;
start_shop = false;
for (int i = 0; i < s; i++) {
scanf("%d", &shop[i]);
if (shop[i] == 0) start_shop = true;
}

sort(shop, shop + s);
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &dis);
E[i] = Edge(u, v, dis, head[u]);
head[u] = i;
}
}

void dijkstra(int s, int *d) {
for (int i = 0; i < n; i++) d[i] = INF;
memset(vis, 0, sizeof(vis));
priority_queue<Node> Q;
d[s] = 0;
Q.push(Node(s, 0));

while (!Q.empty()) {
int u = Q.top().u; Q.pop();

if (vis[u]) continue;
vis[u] = true;
for (int i = head[u]; ~i; i = E[i].next) {
int v = E[i].v;
if (d[v] > d[u] + E[i].dis) {
d[v] = d[u] + E[i].dis;
Q.push(Node(v, d[v]));
}
}
}
}

int bitcount(int x) {
return x ? bitcount(x / 2) + x % 2: 0;
}

void solve() {
dijkstra(0, dis[s]);
for (int i = 0; i < s; i++)
dijkstra(shop[i], dis[i]);
if (dis[s][n - 1] == INF) printf("Case %d: Impossible\n", cas++);
else {
memset(dp, 0x3f, sizeof(dp));
queue<DP> Q;
Q.push(DP(s, 0));
dp[s][0] = 0;

int Max_shop = 0, Min_dis = INF;
while (!Q.empty()) {
int u = Q.front().pos;
int statu = Q.front().statu;
Q.pop();
if (dis[u][n - 1] != INF) {
int t = bitcount(statu);
if (t > Max_shop) {
Max_shop = t;
Min_dis = dis[u][n - 1] + dp[u][statu];
}
else if (t == Max_shop && dp[u][statu] + dis[u][n - 1] < Min_dis) {
Min_dis = dp[u][statu] + dis[u][n - 1];
}
}

for (int i = 0; i < s; i++) {
if (shop[i] == 0 || statu & (1 << i)) continue;
int sta = statu | (1 << i);
if (dp[i][sta] > dp[u][statu] + dis[u][shop[i]]) {
dp[i][sta] = dp[u][statu] + dis[u][shop[i]];
Q.push(DP(i, sta));
}
}
}
Max_shop += start_shop;
printf("Case %d: %d %d\n", cas++, Max_shop, Min_dis);
}
}

int main() {
int test;
scanf("%d", &test);
while (test--) {
init();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: