Problem C. SIRO Challenge JAGain and JAGain Urozero Training Camp, Day 1, DP

Problem C. SIRO Challenge
Input file: standard input
Output file: standard output
Time limit: 1 second
Memory limit: 512 mebibytes
You are now participating in the Summer Training Camp for Programming Contests with your friend
Jiro, who is an enthusiast of the ramen chain SIRO. Since every SIRO restaurant has its own tasteful
ramen, he wants to try them at as many different restaurants as possible in the night. He doesn’t have
plenty of time tonight, however, because he has to get up early in the morning tomorrow to join a training
session. So he asked you to find the maximum number of different restaurants to which he would be able
to go to eat ramen in the limited time.
There are n railway stations in the city, which are numbered 1 through n. The station s is the nearest
to the camp venue. m pairs of stations are directly connected by the railway: you can move between the
stations ai and bi
in ci minutes in the both directions. Among the stations, there are l stations where a
SIRO restaurant is located nearby. There is at most one SIRO restaurant around each of the stations,
and there are no restaurants near the station s. It takes ei minutes for Jiro to eat ramen at the restaurant
near the station ji
.
It takes only a negligibly short time to go back and forth between a station and its nearby SIRO restaurant.
You can also assume that Jiro doesn’t have to wait for the ramen to be served in the restaurants.
Jiro is now at the station s and have to come back to the station in t minutes. How many different SIRO’s
can he taste?
Input
The first line of the input contains five integers: n for the number of stations, m for the number of directly
connected pairs of stations, l for the number of SIRO restaurants, s for the starting-point station, and
t for the time limit for Jiro (2 ≤ n ≤ 300, 1 ≤ m ≤ 5000, 1 ≤ l ≤ 16, 1 ≤ s ≤ n, 1 ≤ t ≤ 105
). Each
of the following m lines contains three integers: ai and bi for the connected stations, and ci for the time
it takes to move between the two stations (1 ≤ ai
, bi ≤ n, 1 ≤ ci ≤ 1000, ai 6= bi
, (ai
, bi) 6= (aj , bj ) and
(ai
, bi) 6= (bj , aj ) for any i 6= j). Each of the following l lines contains two integers: ji for the station where
a SIRO restaurant is located, and ei for the time it takes for Jiro to eat at the restaurant (1 ≤ ji ≤ n,
1 ≤ ei ≤ 15, ji 6= s, all ji are pairwise distinct). Note that there may be some stations not reachable from
the starting point s.
Output
Output the maximum number of different restaurants where Jiro can go within the time limit

看到 l<=16 ,自然应该想到和二进制有关,也就是想到 状压dp ;
考虑 dp[ i ][ j ];
表示i 状态,目前在 j 餐馆的最大数;
先用 floyd 算法处理每两个点的最短路;
然后 dp 即可;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<string>
#include<bitset>
#include<ctime>
#include<deque>
#include<stack>
#include<functional>
#include<sstream>
using namespace std;
#define maxn 200005
#define inf 0x3f3f3f3
#define INF 0x7fffffff
typedef long long ll;
typedef unsigned long long ull;

inline int read()
{
    int x = 0, k = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-')k = -1; c = getchar(); }
    while (c >= '0' && c <= '9')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x * k;
}

int dp[1 << 18][50];
int n, m, l;
int s, t;

int dis[500][500];
int last[50];
int lastT[50];

int main()
{
    //ios::sync_with_stdio(false);
    cin >> n >> m >> l >> s >> t;
    //memset(dis, 0x3f, sizeof(dis));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)dis[i][j] = inf;
    }
    memset(dp, -1, sizeof(dp));
    for (int i = 0; i < n; i++)dis[i][i] = 0;
    for (int i = 0; i < m; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        dis[x - 1][y - 1] = z;
        dis[y - 1][x - 1] = z;
    }
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
    for (int i = 0; i < l; i++) {
        int x, y;
        cin >> x >> y;
        last[i] = x - 1; lastT[i] = y;
    }
    for (int i = 0; i < l; i++) {
        if (dis[s - 1][last[i]] < inf) {
            dp[1 << i][i] = dis[s - 1][last[i]] + lastT[i];
        }
    }
    int cnt, res = 0;
    for (int i = 0; i < (1 << l); i++) {
        cnt = 0;
        for (int j = 0; j < l; j++)if ((1 << j)&i)cnt++;
        for (int j = 0; j < l; j++) {
            if ((1 << j)&i) {
                int temp = i - (1 << j);
                for (int k = 0; k < l; k++) {
                    if (temp&(1 << k) && dis[last[k]][last[j]] < inf&&dp[temp][k] != -1) {
                        if (dp[i][j] == -1) {
                            dp[i][j] = dp[temp][k] + dis[last[k]][last[j]] + lastT[j];
                        }
                        else
                            dp[i][j] = min(dp[i][j], dp[temp][k] + dis[last[k]][last[j]] + lastT[j]);
                    }
                }
                if (dp[i][j] != -1 && dp[i][j] + dis[last[j]][s - 1] <= t)
                    res = max(res, cnt);
            }
        }
    }
    cout << res << endl;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值