2014西安邀请赛部分题解

HDU 4848  Wow! Such Conquering!

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4848

题意及思路:有n个星球,现在你从1开始需要访问其他所有的星球。给你Txy表示从x到y的时间,再给n-1个Deadline表示第一次到星球2~n的最迟时间不能超过所给的Deadline。现在问你是否能在要求内访问所有的星球,如果可以输出最小的时间,否则输出-1。

主体思路是dfs,不过必须要进行剪枝,通过时间是否超过Deadline可以剪去一部分,如果当前应该选取的路径耗时Tij加上之前所用的时间已经大于结果ans,便可枚举下个状态了

 

 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <climits>
#include <utility>

using namespace std;

const int inf = INT_MAX;

int n, ans;
int t[31][31];
int dead[31], vis[31];

void floyd()
{
    for(int k = 0; k < n; k++)
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
            {
                if(t[i][j] > t[i][k] + t[k][j])
                    t[i][j] = t[i][k] + t[k][j];
            }
}

void dfs(int s, int cnt, int ti, int sum)
{
    if(cnt == 0)
    {
        if(ans > sum)
            ans = sum;
        return ;
    }
    for(int i = 0; i < n; i++)
    {
        if(!vis[i] && ti + t[s][i] > dead[i])
            return ;
    }
    for(int i = 0; i < n; i++)
    {
        if(vis[i] || sum + t[s][i] >= ans)
            continue;
        vis[i] = 1;
        dfs(i, cnt - 1, ti + t[s][i], sum + cnt * t[s][i]);
        vis[i] = 0;
    }
}

int main()
{
    int i, j;
    while(~scanf("%d", &n))
    {
        ans = inf;
        memset(vis, 0, sizeof(vis));
        for(i = 0; i < n; i++)
            for(j = 0; j < n; j++)
                scanf("%d", &t[i][j]);
        for(i = 1; i < n; i++)
            scanf("%d", &dead[i]);
        floyd();
        vis[0] = 1;
        dfs(0, n - 1, 0, 0);
        if(ans == inf)
            cout << -1 << endl;
        else
            cout << ans << endl;
    }
    return 0;
}

 

 

HDU 4849  Wow! Such City!

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4849

题意及思路:告诉你两点间的距离公式,然后再用Dijkstra求出0到 其他点的最短路即可

 

 

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long ll;

const int maxd = 1005;
const int maxn = maxd * maxd;
const long long inf = 1e18;

int n, m;
ll x[maxn], y[maxn], z[maxn];
ll c[maxd][maxd], d[maxd];
int vis[maxd];

ll dijstra ()
{
    for (int i = 0; i < n; i++)
        d[i] = inf;
    d[0] = 0;
    vis[0] = 1;
    ll ans = inf;
    for (int i = 0; i < n; i++)
    {
        int p = 0;
        ll tmp = inf;
        for (int j = 0; j < n; j++)
        {
            if (d[j] < tmp && vis[j] == 0)
            {
                p = j;
                tmp = d[j];
            }
        }
        vis[p] = 1;
        if (p != 0 && d[p] % m < ans)
            ans = d[p] % m;
        for (int j = 0; j < n; j++)
        {
            if (d[p] + c[p][j] < d[j])
                d[j] = d[p] + c[p][j];
        }
    }
    return ans;
}

int main ()
{
    while (scanf("%d%d%I64d%I64d%I64d%I64d", &n, &m, &x[0], &x[1], &y[0], &y[1]) == 6)
    {
        memset(vis, 0, sizeof(vis));
        for (int i = 2; i < n * n; i++)
        {
            x[i] = (12345 + x[i - 1] * 23456 + x[i - 2] * 34567 + (x[i - 1] * x[i - 2] % 5837501) * 45678)  % 5837501;
            y[i] = (56789 + y[i - 1] * 67890 + y[i - 2] * 78901 + (y[i - 1] * y[i - 2] % 9860381) * 89012)  % 9860381;
        }
        for(int i = 1; i < n * n; i++)
            z[i] = (x[i] * 90123 + y[i]) % 8475871 + 1;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i == j)
                    c[i][j] = 0;
                else
                    c[i][j] = z[i * n + j];
            }
        }
        printf("%I64d\n", dijstra());
    }
    return 0;
}

 

 

 

HDU 4850  Wow! Such String! 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4850

题意及思路:构造一个长度为N(1 ≤ N ≤ 500000)的小写字母字符串,要求所有长度大于等于4的子串只能出现一次。不能构造输出“Impossible”。

长度大于等于4的子串统一可以转化为长度为4的子串,所能构造出的最大长度为26^4+3,末尾的3个字符共有26^3种组合,每种抽象成一个节点。每个节点添加新字符有26种情况,抽象成26条有向边,指向转化后的节点。每经过一条图中的边,就是构造一个长度为4的子串的过程。由于子串不能重复,那么每条边就至多只能走一次,每个节点的入度和出度均为26,故而存在欧拉回路满足题目要求。

 

直接构造:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <utility>

using namespace std;

const int maxn = 26 * 26 * 26 * 30;

bool vis[26][26][26][26];
int s[maxn], l;

void tc()
{
    int i;
    memset(vis, 0, sizeof(vis));
    for(i = 0; i < 26; i++)
    {
        s[l] = s[l + 1] = s[l + 2] = s[l + 3] = i;
        l += 4;
    }
    for(i = 3; i < l; i++)
        vis[s[i]][s[i - 1]][s[i - 2]][s[i - 3]] = 1;
    while(1)
    {
        int flag = 0;
        for(i = 0; i < 26; i++)
        {
            if(!vis[i][s[l - 1]][s[l - 2]][s[l - 3]])
            {
                flag = 1;
                s[l] = i;
                vis[s[l]][s[l - 1]][s[l - 2]][s[l - 3]] = 1;
                l++;
            }
        }
        if(!flag)
            break;
    }
}


int main()
{
    int n;
    tc();
    while(~scanf("%d", &n))
    {
        if(l < n)
            puts("Impossible");
        else
        {
            for(int i = 0; i < n; i++)
                printf("%c", s[i] + 'a');
            printf("\n");
        }
    }
    return 0;
}

 

 

 

HDU 4856 Tunnels

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4856

题意及思路:给你N*N的网格,‘.’表示可以走,‘#’表示不能走,m条管道,每条管道有起点和终点坐标,Bob每次可以走到相邻的网格花费1s,问走完m条管道要花多少时间,在管道内不计算时间,起点随意

利用BFS和旅行商问题模板解决,不会状态压缩,思路是队友给的=、=

 

 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <utility>

using namespace std;

const int inf = 1e9;

char s[30][30];
int vis[30][30];
int x1[30], x2[30], y1[30], y2[30];
int n, m;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
int d[30][30];
int dp[1 << 15][15];

typedef pair<int, int> p;

void bfs(int x, int y)
{
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            vis[i][j] = inf;
    vis[x][y] = 0;
    queue <p> que;
    que.push(p(x, y));
    while(!que.empty())
    {
        p tq = que.front();
        que.pop();
        for(int i = 0; i < 4; i++)
        {
            int nx = tq.first + dx[i], ny = tq.second + dy[i];
            if(nx > 0 && nx <= n && ny > 0 && ny <= n && vis[nx][ny] == inf && s[nx][ny] != '#')
            {
                que.push(p(nx, ny));
                vis[nx][ny] = vis[tq.first][tq.second] + 1;
            }
        }
    }
}

void solve()
{
    for(int s = 0; s < 1 << m; s++)
    {
        fill(dp[s], dp[s] + m, inf);
    }
    for(int i = 0; i < m; i++)
        dp[(1 << m) - 1][i] = 0;
    for(int s = (1 << m) - 2; s >= 0; s--)
    {
        for(int v = 0; v < m; v++)
        {
            for(int u = 0; u < m; u++)
            {
                if(!(s >> u & 1))
                {
                    dp[s][v] = min(dp[s][v], dp[s | 1 << u][u] + d[v][u]);
                }
            }
        }
    }
}

int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        int i, j, ans = inf;
        for(i = 1; i <= m; i++)
            for(j = 1; j <= m; j++)
            {
                if(i == j)
                    d[i][j] = 0;
                else
                    d[i][j] = inf;
            }
        for(i = 1; i <= n; i++)
            scanf(" %s", s[i] + 1);
        for(i = 1; i <= m; i++)
            scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
        for(i = 1; i <= m; i++)
        {
            bfs(x2[i], y2[i]);
            for(j = 1; j <= m; j++)
            {
                if(i == j)
                    continue;
                d[i - 1][j - 1] = vis[x1[j]][y1[j]];
            }
        }
        solve();
        for(i = 0; i < m; i++)
        {
            ans = min(ans, dp[0][i]);
        }
        if(ans == inf)
            cout << -1 << endl;
        else
            cout << ans << endl;
    }
    return 0;
}

 

 

 

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值