今日训练 简单搜索*2+最短路差分约束*2+并查集*1

Today is another day!

A - 棋盘问题  POJ - 1321 

这个题目是很早之前写的了,但是还是一个很经典的搜索题,这个题目可以很好的让我去理解这个搜索的回溯过程。

这个题目其实挺好写的,如果你想明白了的话。

虽然如此,但是还是写错了,因为我一开始是想只枚举第一行,由第一行推出后面的几行,

但是如果你这么写的话那么如果第一排出现的都是#那么从这里往后递归的一定都会加上一个#,但是可以不一定算第一排的。可以直接从第二排开始排的。

讲的不是很清楚,这个容易让人心态爆炸。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
char s[10][10];
int mp[10][10], c[10];
int n, k;
int ans = 0;
void dfs(int row, int num) {
    if (num == k) {
        ans++;
        return;
    }
    if (num >= n + 1) return;
    if (row >= n + 1) return;
    for(int i=row;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(mp[i][j]&&!c[j])
            {
                c[j] = 1;
                dfs(i + 1, num + 1);
                c[j] = 0;
            }
        }
    }
}

int main() {
    while (scanf("%d%d", &n, &k) == 2) {
        if (n == -1 && k == -1) break;
        ans = 0;
        memset(c, 0, sizeof(c));
        for (int i = 1; i <= n; i++) {
            scanf("%s", s[i] + 1);
            for (int j = 1; j <= n; j++) {
                if (s[i][j] == '#') mp[i][j] = 1;
                else mp[i][j] = 0;
            }
        }
        dfs(1, 0);
        printf("%d\n", ans);
    }
    return 0;
}
dfs

 

B - Dungeon Master POJ - 2251 

就是把二维的变成了三维,注意不要数组越界。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
char s[40][40][40];
int dl[6] = { 0,0,0,0,1,-1 };
int dr[6] = { 1,-1,0,0,0,0 };
int dc[6] = { 0,0,-1,1,0,0 };
int l, r, c, sl, sr, sc;
struct node {
    int l, r, c;
    node(int l = 0, int r = 0, int c = 0) :l(l), r(r), c(c) {}
};
int d[40][40][40];
void bfs() {
    queue<node>que;
    que.push(node(sl, sr, sc));
    memset(d, -1, sizeof(d));
    d[sl][sr][sc] = 0;
    while (!que.empty()) {
        node ex = que.front(); que.pop();
        if (s[ex.l][ex.r][ex.c] == 'E') {
            printf("Escaped in %d minute(s).\n", d[ex.l][ex.r][ex.c]);
            return;
        }
        for (int i = 0; i < 6; i++) {
            int tl = ex.l + dl[i];
            int tr = ex.r + dr[i];
            int tc = ex.c + dc[i];
            if (tl<1 || tr<1 || tc<1 || tl>l || tr>r || tc>c) continue;
            if (s[tl][tr][tc] == '#') continue;
            if (d[tl][tr][tc] >= 0) continue;

            d[tl][tr][tc] = d[ex.l][ex.r][ex.c] + 1;
            que.push(node(tl, tr, tc));
        }
    }
    printf("Trapped!\n");
}

int main() {
    while (scanf("%d%d%d", &l, &r, &c) && (l + r + c)) {
        for (int i = 1; i <= l; i++) {
            for (int j = 1; j <= r; j++) {
                scanf("%s", s[i][j] + 1);
                for (int k = 1; k <= c; k++) {
                    if (s[i][j][k] == 'S') sl = i, sr = j, sc = k;
                }
            }
        }
        bfs();
    }
    return 0;
}
bfs

 

B - King HDU - 1531 

这个是一个差分约束的题目,我觉得还是比较难,建议好好看一下这位大佬的博客 

https://blog.csdn.net/qq_41287489/article/details/79491937

我对于差分约束的理解就是需要建图找到一个合适的松弛条件来满足题目要求。

这个题目的意思是让你判断是不是可以找到一个序列,使得s[a]+s[a+1]+...s[a+b]<k或者>k 这个根据题目条件来。

这个很自然可以想到用前缀和,sum[a+b]-sum[a]<k 或者>k

这个就和最短路或者最长路松弛的条件有点像了。

最短路 d[v]>d[u]+dist 就进行松弛 (即满足条件 d[v]<=d[u]+dist)

最长路 d[v]<d[u]+dist 就进行松弛 (即满足条件 d[v]>=d[u]+dist)

所以我们要这个找到一个满足条件的序列 还需要对上面的 sum[a+b]-sum[a]<k 或者>k  这个式子进行转化。

因为要"<="或者“>=" 才可以用最短路最长路,所以上面的式子要转化成 sum[a+b]-sum[a]<=k-1 或者 >=k+1

因为这个松弛方向必须是一样的,只能用最短路或者最长路。所以还要有一点点的转化。

这个转化就自己想想吧。

这个题目转化完之后就只需要判断负环,所以用spfa。

如果不存在负环,就是说明没有矛盾,可以找到这样的序列,存在负环就说明有矛盾,所以找不到。

我真的好气啊,这个题目我换成链式前向星就过了,vector死活不对,这个题目写了两个多小时,我也是醉了。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
struct node {
    int to, dist, nxt;
}exa[maxn];
int n, m;
int cnt[maxn], d[maxn], head[maxn];
bool inq[maxn];

int tot;
void add(int u, int v, int w) {
    exa[tot].to = v;
    exa[tot].dist = w;
    exa[tot].nxt = head[u];
    head[u] = tot++;
}

bool spfa(int s)//模板
{
    queue<int>que;
    memset(inq, 0, sizeof(inq));
    memset(cnt, 0, sizeof(cnt));
    memset(d, inf, sizeof(d));
    d[s] = 0;
    inq[s] = true;
    que.push(s);

    while (!que.empty()) {
        int u = que.front(); que.pop();
        inq[u] = false;
        for (int i = head[u]; ~i; i=exa[i].nxt) {
            node now = exa[i];
            if (d[now.to] > d[u] + now.dist && d[u] < inf) {
                d[now.to] = d[u] + now.dist;
                if (!inq[now.to]) {
                    que.push(now.to);
                    inq[now.to] = true;
                    if (++cnt[now.to] > n) return false;
                }
            }
        }
    }
    return true;
}


int main() {
    while (scanf("%d", &n) ==1 && n) {
        tot = 0;
        memset(head, -1, sizeof(head));
        scanf("%d", &m);
        for (int i = 1; i <= m; i++) {
            int u, v, k;
            char str[10];
            scanf("%d %d %s %d", &u, &v, str, &k);
            if (str[0] == 'g')    add(u - 1, u + v, -1 - k);
            else add(u + v, u - 1, k - 1);
        }
        int s = n + 1;
        for (int i = 0; i <= n; i++) add(s, i, 0);
        if (spfa(s)) printf("lamentable kingdom\n");
        else printf("successful conspiracy\n");
    }
    return 0;
}
差分约束 最短路

 

N - Layout POJ - 3169 

这个是一个特别简单的差分约束的最短路,这个就可以直接转化一下就可以了,

只是要注意题目给的条件,一个是a<b 一个是有三种情况来输出。

因为题目给的是a<b 所以你可以直接从1开始跑spfa 不然如果你自己设置成了 b>a 那么就需要从 n 开始跑 然后输出d[1]

没看清楚题目条件的我好作死。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
struct node {
    int to, dist, nxt;
}exa[maxn];
int n, m, k;
int cnt[maxn], d[maxn], head[maxn];
bool inq[maxn];

int tot;
void add(int u, int v, int w) {
    exa[tot].to = v;
    exa[tot].dist = w;
    exa[tot].nxt = head[u];
    head[u] = tot++;
}

bool spfa(int s)//模板
{
    queue<int>que;
    memset(inq, 0, sizeof(inq));
    memset(cnt, 0, sizeof(cnt));
    memset(d, inf, sizeof(d));
    d[s] = 0;
    inq[s] = true;
    que.push(s);

    while (!que.empty()) {
        int u = que.front(); que.pop();
        inq[u] = false;
        for (int i = head[u]; ~i; i=exa[i].nxt) {
            node now = exa[i];
            if (d[now.to] > d[u] + now.dist && d[u] < inf) {
                d[now.to] = d[u] + now.dist;
                if (!inq[now.to]) {
                    que.push(now.to);
                    inq[now.to] = true;
                    if (++cnt[now.to] > n) return false;
                }
            }
        }
    }
    return true;
}


int main() {
    while (scanf("%d%d%d",&n,&m,&k)!=EOF) {
        tot = 0;
        memset(head, -1, sizeof(head));
        while(m--)
        {
            int u, v, l;
            scanf("%d%d%d", &u, &v, &l);
            //if (u > v) swap(u, v);
            add(u, v, l);
        }
        while(k--)
        {
            int u, v, l;
            scanf("%d%d%d", &u, &v, &l);
            //if (u > v) swap(u, v);
            add(v, u, -l);
        }
        int ans=spfa(1);
        if (!ans) printf("-1\n");
        else if (d[n] == inf) printf("-2\n");
        else printf("%d\n", d[n]);
    }
    return 0;
}
简单差分约束

 

A - Jungle Roads POJ - 1251 

一个板子题

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
struct node
{
    int u, v, w;
    node(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
}exa[maxn];
int f[maxn];

bool cmp(node a,node b)
{
    return a.w < b.w;
}

int findx(int x)
{
    return f[x] == x ? x : f[x] = findx(f[x]);
}

void unite(int x,int y)
{
    x = findx(x);
    y = findx(y);
    if (x == y) return;
    f[x] = y;
}

bool same(int x,int y)
{
    return findx(x) == findx(y);
}

ll kruskal(int n)
{
    sort(exa, exa + n, cmp);
    ll res = 0;
    for (int i = 0; i < n; i++)
    {
        if (same(exa[i].u,exa[i].v)) continue;
        res += exa[i].w;
        unite(exa[i].u, exa[i].v);
    }
    return res;
}

int main()
{
    int n, cnt = 0;
    while(scanf("%d", &n)!=EOF&&n)
    {
        cnt = 0;
        for (int i = 0; i <= n + 5; i++) f[i] = i;
        for(int i=1;i<n;i++)
        {
            char str[10], ch[10];
            int num, x;
            scanf("%s %d", str, &num);
            int u = str[0] - 'A' + 1;
            for(int j=1;j<=num;j++)
            {
                scanf("%s %d", ch, &x);
                int v = ch[0] - 'A' + 1;
                exa[cnt++] = node(u, v, x);
            }
        }
        ll ans = kruskal(cnt);
        printf("%lld\n", ans);    
    }
    return 0;
}
简单并查集

 

转载于:https://www.cnblogs.com/EchoZQN/p/10996896.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值