Week7 作业

A - TT 的魔法猫

众所周知,TT 有一只魔法猫。
这一天,TT 正在专心致志地玩《猫和老鼠》游戏,然而比赛还没开始,聪明的魔法猫便告诉了 TT 比赛的最终结果。TT 非常诧异,不仅诧异于他的小猫咪居然会说话,更诧异于这可爱的小不点为何有如此魔力?
魔法猫告诉 TT,它其实拥有一张游戏胜负表,上面有 N 个人以及 M 个胜负关系,每个胜负关系为 A B,表示 A 能胜过 B,且胜负关系具有传递性。即 A 胜过 B,B 胜过 C,则 A 也能胜过 C。
TT 不相信他的小猫咪什么比赛都能预测,因此他想知道有多少对选手的胜负无法预先得知,你能帮帮他吗?

Input

第一行给出数据组数。
每组数据第一行给出 N 和 M(N , M <= 500)。
接下来 M 行,每行给出 A B,表示 A 可以胜过 B。

Output

对于每一组数据,判断有多少场比赛的胜负不能预先得知。注意 (a, b) 与 (b, a) 等价,即每一个二元组只被计算一次。

Example Input

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

Example Output

0
0
4

题意:
有一张游戏胜负表,上面若干 个胜负关系,且胜负关系具有传递性,计算出有多少对选手的胜负无法预知。

分析:
本题应该使用Floyd算法,使用一个二维数dis组存储两者间的胜负关系。
从x到y的最短路为min(dis[x][y],dis[x][k]+dis[k][y]),即目前x、y间最短距离 和 x、y通过中间点k连通的距离的较小一方。这里可以进行剪枝,即当dis[x][k]为0时,不论dis[k][y]是否为1,都不能改变dis[x][y]。

代码如下:

#include<iostream>
using namespace std;

int dis[510][510] = { 0 };

int main()
{
	int n, m;
	int num;
	int ans;
	cin >> num;
	while (num--)
	{
		ans = 0;
		cin >> n >> m;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				dis[i][j] = 0;
			}
		};
		for (int j = 0; j < m; j++)
		{
			int a, b;
			cin >> a >> b;
			dis[a - 1][b - 1] = 1;
		}
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				if (dis[j][i] == 1)
				{
					for (int k = 0; k < n; k++)
						dis[j][k] = dis[j][k] | (dis[j][i] & dis[i][k]);
				}
			}
		}
		for (int i = 0; i < n; i++)
		{
			for (int j = i + 1; j < n; j++)
			{
				if (dis[i][j] == 0 && dis[j][i] == 0)
					ans++;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

B - TT 的旅行日记

众所周知,TT 有一只魔法猫。
今天他在 B 站上开启了一次旅行直播,记录他与魔法猫在喵星旅游时的奇遇。 TT 从家里出发,准备乘坐猫猫快线前往喵星机场。猫猫快线分为经济线和商业线两种,它们的速度与价钱都不同。当然啦,商业线要比经济线贵,TT 平常只能坐经济线,但是今天 TT 的魔法猫变出了一张商业线车票,可以坐一站商业线。假设 TT 换乘的时间忽略不计,请你帮 TT 找到一条去喵星机场最快的线路,不然就要误机了!

Input

输入包含多组数据。每组数据第一行为 3 个整数 N, S 和 E (2 ≤ N ≤ 500, 1 ≤ S, E ≤ 100),即猫猫快线中的车站总数,起点和终点(即喵星机场所在站)编号。
下一行包含一个整数 M (1 ≤ M ≤ 1000),即经济线的路段条数。
接下来有 M 行,每行 3 个整数 X, Y, Z (1 ≤ X, Y ≤ N, 1 ≤ Z ≤ 100),表示 TT 可以乘坐经济线在车站 X 和车站 Y 之间往返,其中单程需要 Z 分钟。
下一行为商业线的路段条数 K (1 ≤ K ≤ 1000)。
接下来 K 行是商业线路段的描述,格式同经济线。
所有路段都是双向的,但有可能必须使用商业车票才能到达机场。保证最优解唯一。

Output

对于每组数据,输出3行。第一行按访问顺序给出 TT 经过的各个车站(包括起点和终点),第二行是 TT 换乘商业线的车站编号(如果没有使用商业线车票,输出"Ticket Not Used",不含引号),第三行是 TT 前往喵星机场花费的总时间。
本题不忽略多余的空格和制表符,且每一组答案间要输出一个换行

Example Input

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

Example Output

1 2 4
2
5

题意:
在图中找到一条花费时间最短的路线并输出。

分析:
本题类似于求单源最短路径,但要对商业线进行特殊处理并输出经过的点以及中转的点。
算法思想为从起点和终点分别进行两次dijkstra,分别记录单源最短路,然后对商业线进行枚举并记下使用商业线的最小值,与不使用商业线的最小值进行比较,最后输出最小值。

代码如下:

#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <cmath>
#include <string.h>
using namespace std;

const int inf = 100000000;

struct zhan
{
    int xx, tp;
};

struct edge
{
    int a;
    int to, w;
    bool operator<(const edge& ee)const
    {
        return w > ee.w;
    }
};

int n, S, E;
int m, k, cnt = 0, off = -1;
int dis[510][2];
int road[510];
zhan pre[510][2];
vector<edge> e[510];

void find(int end, int p)
{
    if (end == S) 
    {
        road[cnt] = S;
        cnt++;
        return;
    }
    zhan before = pre[end][p];
    if (before.tp == 1)
    {
        off = before.xx;
        p = 0;
    }
    find(before.xx, p);
    road[cnt] = end;
    cnt++;
    return;
}

int main()
{
    int kk = 0;
    while (scanf("%d", &n) != EOF)
    {
        scanf("%d %d", &S, &E);
        scanf("%d", &m);
        for (int i = 0; i < m; i++)
        {
            int f, t, ww;
            scanf("%d %d %d", &f, &t, &ww);
            e[f].push_back({ 0, t, ww });
            e[t].push_back({ 0, f, ww });
        }
        scanf("%d", &k);
        for (int i = 0; i < k; i++)
        {
            int f, t, ww;
            scanf("%d %d %d", &f, &t, &ww);
            e[f].push_back({ 1, t, ww });
            e[t].push_back({ 1, f, ww });
        }
        priority_queue<edge> q;
        memset(pre, 0, sizeof(pre));
        for (int i = 0; i < 510; i++)
        {
            dis[i][0] = inf;
            dis[i][1] = inf;
        }
        dis[S][0] = 0;
        dis[S][1] = 0;
        q.push({ 0, S, 0 });
        while (!q.empty())
        {
            int x = q.top().to;
            q.pop();
            for (int i = 0; i < e[x].size(); i++)
            {
                int y = e[x][i].to, ww = e[x][i].w, t = e[x][i].a;
                if (!t)
                {
                    if (dis[y][0] > dis[x][0] + ww)
                    {
                        zhan pp;
                        pp.xx = x;
                        pp.tp = t;
                        pre[y][0] = pp;
                        dis[y][0] = dis[x][0] + ww;
                        q.push({ 0, y, dis[y][0] });
                    }
                    if (dis[y][1] > dis[x][1] + ww)
                    {
                        zhan pp;
                        pp.xx = x;
                        pp.tp = t;
                        pre[y][1] = pp;
                        dis[y][1] = dis[x][1] + ww;
                        q.push({ 1, y, dis[y][1] });
                    }
                }
                else
                {
                    if (dis[y][1] > dis[x][0] + ww)
                    {
                        zhan pp;
                        pp.xx = x;
                        pp.tp = t;
                        pre[y][1] = pp;
                        dis[y][1] = dis[x][0] + ww;
                        q.push({ 1, y, dis[y][1] });
                    }
                }
            }
        }
        cnt = 0;    
        off = -1;
        int ans;
        memset(road, 0, sizeof(road));
        if (dis[E][0] < dis[E][1])
        {
            ans = dis[E][0];
            find(E, 0);
        }
        else
        {
            ans = dis[E][1];
            find(E, 1);
        }
        if (!kk)		
            kk = 1;
        else	
            printf("\n");
        for (int i = 0; i < cnt; i++)
        {
            if (i != cnt - 1)  
                printf("%d ", road[i]);
            if (i == cnt - 1)  
                printf("%d\n", road[i]);
        }
        if (off == -1)   
            printf("Ticket Not Used\n");
        else    
            printf("%d\n", off);
        printf("%d\n", ans);
        for (int i = 0; i < 510; i++)      
            e[i].clear();
    }
    return 0;
}

C - TT 的美梦

这一晚,TT 做了个美梦!
在梦中,TT 的愿望成真了,他成为了喵星的统领!喵星上有 N 个商业城市,编号 1 ~ N,其中 1 号城市是 TT 所在的城市,即首都。
喵星上共有 M 条有向道路供商业城市相互往来。但是随着喵星商业的日渐繁荣,有些道路变得非常拥挤。正在 TT 为之苦恼之时,他的魔法小猫咪提出了一个解决方案!TT 欣然接受并针对该方案颁布了一项新的政策。
具体政策如下:对每一个商业城市标记一个正整数,表示其繁荣程度,当每一只喵沿道路从一个商业城市走到另一个商业城市时,TT 都会收取它们(目的地繁荣程度 - 出发地繁荣程度)^ 3 的税。
TT 打算测试一下这项政策是否合理,因此他想知道从首都出发,走到其他城市至少要交多少的税,如果总金额小于 3 或者无法到达请悄咪咪地打出 ‘?’。

Input

第一行输入 T,表明共有 T 组数据。(1 <= T <= 50)
对于每一组数据,第一行输入 N,表示点的个数。(1 <= N <= 200)
第二行输入 N 个整数,表示 1 ~ N 点的权值 a[i]。(0 <= a[i] <= 20)
第三行输入 M,表示有向道路的条数。(0 <= M <= 100000)
接下来 M 行,每行有两个整数 A B,表示存在一条 A 到 B 的有向道路。
接下来给出一个整数 Q,表示询问个数。(0 <= Q <= 100000)
每一次询问给出一个 P,表示求 1 号点到 P 号点的最少税费。

Output

每个询问输出一行,如果不可达或税费小于 3 则输出 ‘?’。

Example Input

2
5
6 7 8 9 10
6
1 2
2 3
3 4
1 5
5 4
4 5
2
4
5
10
1 2 4 4 5 6 7 8 9 10
10
1 2
2 3
3 1
1 4
4 5
5 6
6 7
7 8
8 9
9 10
2
3 10

Example Output

Case 1:
3
4
Case 2:
?
?

题意:
在图中找出某个节点到剩余每个节点的最小消耗路线。

分析:
该题要求单源最短路径,并且存在负边的情况,只能用SPFA算法。
先将起点到所有点的距离初始化为inf并将起点入队,当队列不为空时,每次取队首元素,将其出队并将label值修改为0。当点出现在队列中的次数大于等于图中的点数时,存在负环,输出“?”,当要缴纳的税小于3时也输出“?”。

代码如下:

#include<iostream>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;

const int inf = 1000000000;

struct city 
{
	int e;
	int mo;
};

int T, N, M, Q, P;
int a[210], dis[210], in[210], cnt[210], fu[210], label[210];

void init()
{
	for (int i = 0; i < 210; i++)
	{
		dis[i] = inf;
		in[i] = cnt[i] = fu[i] = label[i] = 0;
	}
}

void SPFA(vector<city> ro[210])
{
	queue<int> q;
	dis[1] = 0;
	in[1] = 1;
	q.push(1);
	while (!q.empty())
	{
		int num = q.front();
		q.pop();
		in[num] = 0;
		for (int i = 0; i < ro[num].size(); i++)
		{
			int end = ro[num][i].e;
			int m = ro[num][i].mo;
			if (dis[end] > (dis[num] + m))
			{
				dis[end] = dis[num] + m;
				cnt[end] = cnt[num] + 1;
				if (cnt[end] >= N)
				{
					fu[end] = 1;
					queue<int> p;
					p.push(end);
					label[end] = 1;
					while (!p.empty())
					{
						int ff = p.front();
						p.pop();
						for (int k = 0; k < ro[ff].size(); k++)
						{
							int temp = ro[ff][k].e;
							fu[temp] = 1;
							if (label[temp] == 0)
							{
								label[temp] = 1;
								p.push(temp);
							}
						}
					}
				}
				if ((in[end] != 1) && fu[end] == 0)
				{
					q.push(end);
					in[end] = 1;
				}
			}
		}
	}
}

int main()
{
	cin >> T;
	int t = T;
	while (T--)
	{
		vector<city> road[210];
		cin >> N;
		for (int i = 1; i <= N; i++)
			cin >> a[i];
		cin >> M;
		for (int i = 0; i < M; i++)
		{
			int A, B;
			cin >> A >> B;
			city c;
			c.e = B;
			c.mo = pow((a[B] - a[A]), 3);
			road[A].push_back(c);
		}
		init();
		SPFA(road);
		cin >> Q;
		cout << "Case " << t - T << ":" << endl;
		for (int i = 0; i < Q; i++)
		{
			cin >> P;
			if (dis[P] == inf || fu[P] == 1 || dis[P] < 3)
				cout << "?" << endl;
			else
				cout << dis[P] << endl;
		}
	}
	return 0;
}
发布了14 篇原创文章 · 获赞 0 · 访问量 291

猜你喜欢

转载自blog.csdn.net/qq_43808194/article/details/105572071
今日推荐