题意 求把所有数加起来的最小代价a+b的代价为(a+b)

越先运算的数 要被加的次数越多 所以每次相加的两个数都应该是剩下序列中最小的数 然后结果要放到序列中 也就是优先队列了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<cstdio>
#include<queue>
using namespace std;
priority_queue<int, vector<int>, greater<int> >q;
typedef long long ll;
ll ans;
int main()
{
int n, t;
while(scanf("%d", &n), n)
{
for(int i = 0; i < n; ++i)
{
scanf("%d", &t);
q.push(t);
}

ans = 0;
while(!q.empty())
{
int a = q.top(); q.pop();
int b = q.top(); q.pop();
ans += (a + b);
if(q.empty()) break;
q.push(a + b);
}
printf("%lld\n", ans);
}
return 0;
}

Yup!! The problem name reflects your task; just add a set of numbers. But you may feel yourselves condescended, to write a C/C++ program just to add a set of numbers. Such a problem will simply question your erudition. So, let’s add some flavor of ingenuity to it.

Addition operation requires cost now, and the cost is the summation of those two to be added. So, to add 1 and 10, you need a cost of11. If you want to add 1, 2 and 3. There are several ways –

1 + 2 = 3, cost = 3

3 + 3 = 6, cost = 6

Total = 9

1 + 3 = 4, cost = 4

2 + 4 = 6, cost = 6

Total = 10

2 + 3 = 5, cost = 5

1 + 5 = 6, cost = 6

Total = 11

I hope you have understood already your mission, to add a set of integers so that the cost is minimal.

Input

Each test case will start with a positive number, N (2 ≤ N ≤ 5000) followed by N positive integers (all are less than 100000). Input is terminated by a case where the value of N is zero. This case should not be processed.

Output

For each case print the minimum total cost of addition in a single line.

Sample Input Output for Sample Input

3

1 2 3

4

1 2 3 4

0


9

19



题意 一个城市原来有l个村庄 e1条道路 又增加了n个村庄 e2条道路 后来后销毁了m个村庄 与m相连的道路也销毁了 求使所有未销毁村庄相互连通最小花费 不能连通输出what a pity!

还是很裸的最小生成树 把销毁掉的标记下 然后prim咯 结果是无穷大就是不能连通的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 300;
int mat[N][N], des[N], d[N], ans, n, m;

void prim()
{
memset(d, 0x3f, sizeof(d));
int s = 0; while(des[s]) ++s;
d[s] = -1;
int cur = s, next = n;
for(int k = 1; k < n - m; ++k)
{
for(int i = 0; i < n; ++i)
{
if(des[i] || d[i] < 0) continue;
d[i] = min(d[i], mat[cur][i]);
if(d[i] < d[next]) next = i;
}
ans += d[next], d[next] = -1, cur = next, next = n;
}
}

int main()
{
int cas, l, e1, e2, a, b, c;
scanf("%d", &cas);
while(cas--)
{
memset(mat, 0x3f, sizeof(mat));
memset(des, 0, sizeof(des));
scanf("%d %d", &l, &e1);
for(int i = 0; i < e1; ++i)
{
scanf("%d%d%d", &a, &b, &c);
if(c < mat[a][b]) mat[a][b] = mat[b][a] = c;
}

scanf("%d %d", &n, &e2);
for(int i = 0; i < e2; ++i)
{
scanf("%d%d%d", &a, &b, &c);
if(c < mat[a][b]) mat[a][b] = mat[b][a] = c;
}

n = n + l;
scanf("%d", &m);
for(int i = 0; i < m; ++i)
{
scanf("%d", &a);
des[a] = 1;
}

ans = 0; prim();
if(ans < d[n]) printf("%d\n", ans);
else printf("what a pity!\n");
}
return 0;
}

The plan of city rebuild

Problem Description

News comes!~City W will be rebuilt with the expectation to become a center city. There are some villages and roads in the city now, however. In order to make the city better, some new villages should be built and some old ones should be destroyed. Then the officers have to make a new plan, now you , as the designer, have the task to judge if the plan is practical, which means there are roads(direct or indirect) between every two villages(of course the village has not be destroyed), if the plan is available, please output the minimum cost, or output”what a pity!”.
Input

Input contains an integer T in the first line, which means there are T cases, and then T lines follow.
Each case contains three parts. The first part contains two integers l(0<l<100), e1, representing the original number of villages and roads between villages(the range of village is from 0 to l-1), then follows e1 lines, each line contains three integers a, b, c (0<=a, b<l, 0<=c<=1000), a, b indicating the village numbers and c indicating the road cost of village a and village b . The second part first contains an integer n(0<n<100), e2, representing the number of new villages and roads(the range of village is from l to l+n-1), then follows e2 lines, each line contains three integers x, y, z (0<=x, y<l+n, 0<=z<=1000), x, y indicating the village numbers and z indicating the road cost of village x and village y. The third part contains an integer m(0<m<l+n), representing the number of deserted villages, next line comes m integers, p1,p2,…,pm,(0<=p1,p2,…,pm<l+n) indicating the village number.
Pay attention: if one village is deserted, the roads connected are deserted, too.
Output

For each test case, If all villages can connect with each other(direct or indirect), output the minimum cost, or output “what a pity!”.
Sample Input

2 4 5 0 1 10 0 2 20 2 3 40 1 3 10 1 2 70 1 1 4 1 60 2 2 3 3 3 0 1 20 2 1 40 2 0 70 2 3 0 3 10 1 4 90 2 4 100 0
Sample Output

70 160

题意 见下方中文翻译

每个单词可以看成首尾两个字母相连的一条边 然后就是输入m条边 判断能否构成有向欧拉通路了

有向图存在欧拉通路的充要条件:

  1. 有向图的基图连通;

  2. 所有点的出度和入度相等或者只有两个入度和出度不相等的点 且这两点入度与出度的差一个为-1(起点)一个为1(终点).

判断是否连通就是应用并查集了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 30, M = 100010;
struct edge{int u, v; } e[M];
int vis[N], in[N], out[N], par[N], m, ok;

int Find(int x)
{
int r = x, tmp;
while(par[r] >= 0) r = par[r];
while(x != r)
{
tmp = par[x];
par[x] = r;
x = tmp;
}
return r;
}

void Union(int u, int v)
{
int ru = Find(u), rv = Find(v), tmp = par[ru] + par[rv];
if(par[ru] < par[rv]) par[rv] = ru, par[ru] = tmp;
else par[ru] = rv, par[rv] = tmp;
}

void connect()
{
memset(par, -1, sizeof(par)); //初始化并查集
for(int i = 0; i < m; ++i)
{
int u = e[i].u, v = e[i].v;
if(Find(u) != Find(v)) Union(u, v);
}
for(int i = 0; i < 26; ++i)
for(int j = 0; j < 26; ++j)
if(vis[i] && vis[j] && Find(i) != Find(j)) ok = 0;
}

int main()
{
char s[1005];
int u, v, cas;
scanf("%d", &cas);
while(cas--)
{
for(int i = 0; i < 26; ++i)
vis[i] = in[i] = out[i] = 0;
scanf("%d", &m);
for(int i = 0; i < m; ++i)
{
scanf("%s", s);
u = s[0] - 'a', v = s[strlen(s) - 1] - 'a';
vis[u] = vis[v] = 1;
e[i].u = u, e[i].v = v;
++in[u], ++out[v];
}

int id = 0, od = 0;//i[d]记录入度比出度大1的点的个数 o[d]小1
ok = 1;
for(int i = 0; i < 26; ++i)
{
if(!vis[i]) continue;
int k = in[i] - out[i];
if(k < -1 || k > 1) {ok = 0; break;}
if(k == 1) ++id;
if(k == -1) ++od;
}
if(id > 1 || od > 1 || id - od) ok = 0;
connect();
if(ok) printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}

题目描述:
有些秘门带有一个有趣的词迷。考古学家必须解开词迷才能打开门。由于没有其他方法可以 打开门,因此词迷就变得很重要。 每个门上有许多磁盘。每个盘上有一个单词,这些磁盘必须重新排列使得每个单词第一个字 母跟前一个单词后一个字母相同。例如单词”acm”可以跟在单词”motorola”的后面。你的任务是 编写一个程序,读入一组单词,然后判定是否可以经过重组使得每个单词第一个字母跟前一个单 词后一个字母相同,这样才能打开门。

输入描述:

输入文件中包含 T 个测试数据。输入文件的第一行就是 T,接下来是 T 个测试数据。每个测 试数据的第一行是一个整数 N,表示单词的个数(1≤N≤100000);接下来有 N行,每行是一个 单词;每个单词至少有 2个、至多有 1000 个小写字母,即单词中只可能出现字母’a’~’z’;在同一 个测试数据中,一个单词可能出现多次。

输出描述:

如果通过重组单词可以达到要求,输出”Ordering is possible.”,否则输出”The door cannot be opened.”。

Sample Input
3 2 acm ibm 3 acm malform mouse 2 ok ok

Sample Output

The door cannot be opened. Ordering is possible. The door cannot be opened.

题目描述:

你是一座大庄园的管家。庄园有很多房间,编号为 0、1、2、3,…。你的主人是一个心不在 焉的人,经常沿着走廊随意地把房间的门打开。多年来,你掌握了一个诀窍:沿着一个通道,穿 过这些大房间,并把房门关上。你的问题是能否找到一条路径经过所有开着门的房间,并使得: 1) 通过门后立即把门关上; 2) 关上了的门不再打开; 3) 后回到你自己的房间(房间 0),并且所有的门都已经关闭了。 在本题中,给定房间列表,及连通房间的、开着的门,并给定一个起始房间,判断是否存在 这样的一条路径。不需要输出这样的路径,只需判断是否存在。假定任意两个房间之间都是连通 的(可能需要经过其他房间)。

输入描述:

输入文件包含多个(多可达 100 个)测试数据,每个测试数据之间没有空行隔开。 每个测试数据包括 3部分: 起始行-格式为“START M N”,其中 M 为管理员起始所处的房间号,N 为房间的总数(1 ≤N≤20); 房间列表-一共 N行,每行列出了一个房间通向其他房间的房间号(只需列出比它的号码大 的房间号,可能有多个,按升序排列),比如房间 3有门通向房间 1、5、7,则房间 3的信息行内 容为“5 7”,第一行代表房间 0,后一行代表行间 N-1。有可能有些行为空行,当然后一行肯 定是空行,因为 N-1 是大的房间号;两个房间之间可能有多扇门连通。 终止行-内容为”END”。 输入文件后一行是”ENDOFINPUT”,表示输入结束。

输出描述:

每个测试数据对应一行输出,如果能找到一条路关闭所有的门,并且回到房间 0,则输出”YES X”,X是他关闭的门的总数,否则输出”NO”。

就是判断能否构成欧拉通路·咯

无向图存在欧拉通路的充要条件:

  1. 是连通图

  2. 奇度节点个数为0或2,其中为0时为欧拉回路,为2时是以这两个点节点为端点的欧拉通路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<cstdio>
#include<cstring>
#include<cctype>
const int N = 21;
using namespace std;

int main()
{
int door, cnt, m, n, deg[N];
char s[N], c;
while(~scanf("%s", s), strcmp(s, "ENDOFINPUT"))
{
memset(deg, 0, sizeof(deg));
door = cnt = 0;
scanf("%d %d\n", &m, &n);
for(int i = 0; i < n; ++i)
{
while(scanf("%c", &c))
{
if(isdigit(c)) ++door, ++deg[i], ++deg[c - '0'];
else if(c == ' ') continue;
else break;
}
if(deg[i] % 2) ++cnt;
}

scanf("%s", s);
bool ok = (cnt == 0 && m == 0 ) || (m && cnt == 2 && deg[m] % 2 );
if(ok) printf("YES %d\n", door);
else printf("NO\n");
}
return 0;
}

Door Man

Description
You are a butler in a large mansion. This mansion has so many rooms that they are merely referred to by number (room 0, 1, 2, 3, etc…). Your master is a particularly absent-minded lout and continually leaves doors open throughout a particular floor of the house. Over the years, you have mastered the art of traveling in a single path through the sloppy rooms and closing the doors behind you. Your biggest problem is determining whether it is possible to find a path through the sloppy rooms where you:
Always shut open doors behind you immediately after passing through
Never open a closed door
End up in your chambers (room 0) with all doors closed
In this problem, you are given a list of rooms and open doors between them (along with a starting room). It is not needed to determine a route, only if one is possible.

Input

Input to this problem will consist of a (non-empty) series of up to 100 data sets. Each data set will be formatted according to the following description, and there will be no blank lines separating data sets.
A single data set has 3 components:
Start line - A single line, “START M N”, where M indicates the butler’s starting room, and N indicates the number of rooms in the house (1 <= N <= 20).
Room list - A series of N lines. Each line lists, for a single room, every open door that leads to a room of higher number. For example, if room 3 had open doors to rooms 1, 5, and 7, the line for room 3 would read “5 7”. The first line in the list represents room 0. The second line represents room 1, and so on until the last line, which represents room (N - 1). It is possible for lines to be empty (in particular, the last line will always be empty since it is the highest numbered room). On each line, the adjacent rooms are always listed in ascending order. It is possible for rooms to be connected by multiple doors!
End line - A single line, “END”
Following the final data set will be a single line, “ENDOFINPUT”.
Note that there will be no more than 100 doors in any single data set.

Output

For each data set, there will be exactly one line of output. If it is possible for the butler (by following the rules in the introduction) to walk into his chambers and close the final open door behind him, print a line “YES X”, where X is the number of doors he closed. Otherwise, print “NO”.

Sample Input

START 1 2 1 END START 0 5 1 2 2 3 3 4 4 END START 0 10 1 9 2 3 4 5 6 7 8 9 END ENDOFINPUT

Sample Output

YES 1 NO YES 10

题意 中文 就是求小于等于n的数中有多少个和n互质 即欧拉函数值

div[i] 表示i的最小质因数 eul[i]存储i的欧拉函数值

求欧拉函数的方法:

1.eul[1]=1;

  1. 若i==p^k (p是素数)eul[i]=(p-1)/*p^(k-1);

  2. 若m,n互质, eul[m/*n]=eul[m]/*eul[n];

可以推出欧拉函数的递推式

若(i/div[i])%div[i]==0 则 eul[i]=eul[i/div[i]]/div[i]否则eul[i]=eul[i/div[i]]/(div[i] -1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 33000;
int div[N], eul[N];

void geneuller()
{
for(int i = 1; i < N; ++i) div[i] = i;
for(int i = 2; i * i < N; ++i)
{
if(div[i] == i)
for(int j = i * i; j < N; j += i) div[j] = i;
}

eul[1] = 1;
for(int i = 2; i < N; ++i)
{
eul[i] = eul[i / div[i]];
if((i / div[i]) % div[i] == 0) eul[i] *= div[i];
else eul[i] *= div[i] - 1;
}
}

int main()
{
int cas, n;
geneuller();
scanf("%d", &cas);
while(cas--)
{
scanf("%d", &n);
printf("%d\n", eul[n]);
}
return 0;
}

找新朋友

Problem Description

新年快到了,“猪头帮协会”准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大于1的公约数,否则都是新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。
Input

第一行是测试数据的组数CN(Case number,1<CN<10000),接着有CN行正整数N(1<n<32768),表示会员人数。
Output

对于每一个N,输出一行新朋友的人数,这样共有CN行输出。
Sample Input

2 25608 24027
Sample Output

7680 16016

题意 求一个序列的所有上升子序列中第二长的那个的长度

简单的dp d[i]表示以第i个数结尾的最长上升子序列的长度 c[i]表示到达d[i]的方法数 如序列1 1 2 d[3]=2,c[3]=2 因为选1 3位置和 2 3位置的都可以得到d[3]=2 递推过程很简单 d[i]=max{d[j]+1}其中a[i]>a[j]&&i>j

最后看d[1~n]中最大的数出现了几次 出现了不止一次就直接输出否则就减一输出咯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1005;
int n, a[N];
int d[N], c[N], cas, ans;

int main()
{
scanf("%d", &cas);
while (cas--)
{
scanf("%d", &n);
int sum = ans = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
d[i] = 1, c[i] = 1;
for (int j = 1; j < i; ++j)
{
if (a[j] >= a[i]) continue;
if (d[j] + 1 > d[i])
{
d[i] = d[j] + 1;
c[i] = c[j];
}
else if (d[j] + 1 == d[i]) c[i] = 2;
}
if(d[i] > ans) ans = d[i];
}
for (int i = 1; i <= n; ++i)
if (d[i] == ans) sum += c[i];
printf("%d\n", sum > 1 ? ans : ans - 1);
}
return 0;
}

Revenge of LIS II

Problem Description

In computer science, the longest increasing subsequence problem is to find a subsequence of a given sequence in which the subsequence’s elements are in sorted order, lowest to highest, and in which the subsequence is as long as possible. This subsequence is not necessarily contiguous, or unique.
—Wikipedia
Today, LIS takes revenge on you, again. You mission is not calculating the length of longest increasing subsequence, but the length of the second longest increasing subsequence.
Two subsequence is different if and only they have different length, or have at least one different element index in the same place. And second longest increasing subsequence of sequence S indicates the second largest one while sorting all the increasing subsequences of S by its length.
Input

The first line contains a single integer T, indicating the number of test cases.
Each test case begins with an integer N, indicating the length of the sequence. Then N integer Ai follows, indicating the sequence.
[Technical Specification]

  1. 1 <= T <= 100
  2. 2 <= N <= 1000
  3. 1 <= Ai <= 1 000 000 000
    Output

For each test case, output the length of the second longest increasing subsequence.
Sample Input

3 2 1 1 4 1 2 3 4 5 1 1 2 2 2
Sample Output

1 3 2

HintFor the first sequence, there are two increasing subsequence: [1], [1]. So the length of the second longest increasing subsequence is also 1, same with the length of LIS.

题意 给你n个点的坐标 求第1个点到第2个点的所有路径中两点间最大距离的最小值

很水的floyd咯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
double d[N][N];
int x[N],y[N],n;

void floyd()
{
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));
}

int main()
{
int cas=0;
while(scanf("%d",&n),n)
{
memset(d,0x3f,sizeof(d));
for(int i=1;i<=n;++i)
{
scanf("%d%d",&x[i],&y[i]);
for(int j=1;j<i;++j)
{
int tx=x[i]-x[j],ty=y[i]-y[j];
d[i][j]=d[j][i]=sqrt(tx*tx+ty*ty);
}
}
floyd();
printf("Scenario #%d\nFrog Distance = %.3f\n\n",++cas,d[1][2]);
}
return 0;
}

Frogger

Description
Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sitting on another stone. He plans to visit her, but since the water is dirty and full of tourists’ sunscreen, he wants to avoid swimming and instead reach her by jumping.
Unfortunately Fiona’s stone is out of his jump range. Therefore Freddy considers to use other stones as intermediate stops and reach her by a sequence of several small jumps.
To execute a given sequence of jumps, a frog’s jump range obviously must be at least as long as the longest jump occuring in the sequence.
The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones.
You are given the coordinates of Freddy’s stone, Fiona’s stone and all other stones in the lake. Your job is to compute the frog distance between Freddy’s and Fiona’s stone.

Input

The input will contain one or more test cases. The first line of each test case will contain the number of stones n (2<=n<=200). The next n lines each contain two integers xi,yi (0 <= xi,yi <= 1000) representing the coordinates of stone /#i. Stone /#1 is Freddy’s stone, stone /#2 is Fiona’s stone, the other n-2 stones are unoccupied. There’s a blank line following each test case. Input is terminated by a value of zero (0) for n.

Output

For each test case, print a line saying “Scenario /#x” and a line saying “Frog Distance = y” where x is replaced by the test case number (they are numbered from 1) and y is replaced by the appropriate real number, printed to three decimals. Put a blank line after each test case, even after the last one.

Sample Input

2 0 0 3 4 3 17 4 19 4 18 5 0

Sample Output

Scenario /#1 Frog Distance = 5.000 Scenario /#2 Frog Distance = 1.414

Source

Ulm Local 1997

题目翻译

一些公司决定搭建一个更快的网络,称为“光纤网”。他们已经在全世界建立了许多站点,这 些站点的作用类似于路由器。不幸的是,这些公司在关于站点之间的接线问题上存在争论,这样“光纤网”项目就被迫终止了,留下的是每个公司自己在某些站点之间铺设的线路。 现在,Internet 服务供应商,当想从站点 A传送数据到站点 B,就感到困惑了,到底哪个公司 能够提供必要的连接。请帮助供应商回答他们的查询,查询所有可以提供从站点 A到站定 B的线 路连接的公司。

输入描述:

输入文件包含多个测试数据。每个测试数据第 1行为一个整数 n,代表网络中站点的个数,n = 0 代表输入结束,否则 n的范围为:1≤n≤200。站点的编号为 1, …, n。接下来列出了这些站 点之间的连接。每对连接占一行,首先是两个整数 A和B,A = B = 0 代表连接列表结束,否则 A、 B的范围为:1≤A, B≤n,表示站点 A和站点 B之间的单向连接;每行后面列出了拥有站点 A到 B之间连接的公司,公司用小写字母标识,多个公司的集合为包含小写字母的字符串。 连接列表之后,是供应商查询的列表。每个查询包含两个整数 A和B,A = B = 0 代表查询列 表结束,也代表整个测试数据结束,否则 A、B 的范围为:1≤A, B≤n,代表查询的起始和终止 站点。假定任何一对连接和查询的两个站点都不相同。

输出描述:

对测试数据中的每个查询,输出一行,为满足以下条件的所有公司的标识:这些公司可以通 过自己的线路为供应商提供从查询的起始站点到终止站点的数据通路。如果没有满足条件的公司, 则仅输出字符”-“。每个测试数据的输出之后输出一个空行。

公司最多有26个 可以用2进制来表示站点间的连接关系 如果提供站点 1 到站点 2 的连接的公司集合为{ ‘a’, ‘b’, ‘c’ },可以用 “00000000000000000000000000000111”表示,提供站点 2到站点 3的连接的公司集合为{ ‘a’, ‘d’ },用“00000000000000000000000000001001”表示,这两个整数进行二进制与运算后 得到“00000000000000000000000000000001”,表示通过中间站点 2,提供站点 1到站点 3的连 接的公司集合为{ ‘a’ }。

这样就floyd进行处理就类似最短路问题了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 205;
int d[N][N], n;

void floyd()
{
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
d[i][j] |= (d[i][k] & d[k][j]);

}

int main()
{
int a, b;
char s[30];
while(scanf("%d", &n), n)
{
memset(d, 0, sizeof(d));
while(scanf("%d%d", &a, &b), a)
{
scanf("%s", s);
for(int i = 0; s[i] != '\0'; ++i)
d[a][b] = d[a][b] | (1 << s[i] - 'a');
}
floyd();
while(scanf("%d%d", &a, &b), a)
{
for(char c = 'a'; c <= 'z'; ++c)
if(d[a][b] & (1 << c - 'a')) printf("%c", c);
if(d[a][b] == 0) printf("-");
printf("\n");
}
printf("\n");
}
return 0;
}

Fiber Network

Description
Several startup companies have decided to build a better Internet, called the “FiberNet”. They have already installed many nodes that act as routers all around the world. Unfortunately, they started to quarrel about the connecting lines, and ended up with every company laying its own set of cables between some of the nodes.
Now, service providers, who want to send data from node A to node B are curious, which company is able to provide the necessary connections. Help the providers by answering their queries.

Input

The input contains several test cases. Each test case starts with the number of nodes of the network n. Input is terminated by n=0. Otherwise, 1<=n<=200. Nodes have the numbers 1, …, n. Then follows a list of connections. Every connection starts with two numbers A, B. The list of connections is terminated by A=B=0. Otherwise, 1<=A,B<=n, and they denote the start and the endpoint of the unidirectional connection, respectively. For every connection, the two nodes are followed by the companies that have a connection from node A to node B. A company is identified by a lower-case letter. The set of companies having a connection is just a word composed of lower-case letters.
After the list of connections, each test case is completed by a list of queries. Each query consists of two numbers A, B. The list (and with it the test case) is terminated by A=B=0. Otherwise, 1<=A,B<=n, and they denote the start and the endpoint of the query. You may assume that no connection and no query contains identical start and end nodes.

Output

For each query in every test case generate a line containing the identifiers of all the companies, that can route data packages on their own connections from the start node to the end node of the query. If there are no companies, output “-“ instead. Output a blank line after each test case.

Sample Input

3 1 2 abc 2 3 ad 1 3 b 3 1 de 0 0 1 3 2 1 3 2 0 0 2 1 2 z 0 0 1 2 2 1 0 0 0

Sample Output

ab d - z -

题意 给你一个无向图的邻接矩阵 和途径每个点需要的额外花费首尾没有额外花费 求图中某两点之间的最短路并打印字典序最小路径

要求多组点之间的就用floyd咯 打印路径也比较方便 nex[i][j]表示从i点到j点最短路的第一个途经点 那么如果路径中加入一个节点k后 nex[i][j]应该更新为nex[i][k] 因为要途径k了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100,INF=0x3f3f3f;
int cost[N][N], tax[N], nex[N][N];
int s, t, n;

void floyd()
{
int tmp;
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
{
tmp = cost[i][k] + cost[k][j] + tax[k];
if(cost[i][j] > tmp || (cost[i][j] == tmp && nex[i][j] > nex[i][k]))
{
nex[i][j] = nex[i][k];
cost[i][j] = tmp;
}
}
}

int main()
{
while(scanf("%d", &n), n)
{
memset(nex,0,sizeof(nex));
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
{
scanf("%d", &cost[i][j]);
if(cost[i][j] < 0) cost[i][j]=INF;
else nex[i][j]=j;
}
}

for(int i = 1; i <= n; ++i) scanf("%d", &tax[i]);
floyd();
while(scanf("%d%d", &s, &t), s > 0)
{
int k=s;
printf("From %d to %d :\nPath: %d", s, t, s);
while(k!=t) printf("-->%d", k=nex[k][t]);
printf("\nTotal cost : %d\n\n", cost[s][t]);
}
}
return 0;
}

Minimum Transport Cost

Problem Description

These are N cities in Spring country. Between each pair of cities there may be one transportation track or none. Now there is some cargo that should be delivered from one city to another. The transportation fee consists of two parts:
The cost of the transportation on the path between these cities, and
a certain tax which will be charged whenever any cargo passing through one city, except for the source and the destination cities.
You must write a program to find the route which has the minimum cost.
Input

First is N, number of cities. N = 0 indicates the end of input.
The data of path cost, city tax, source and destination cities are given in the input, which is of the form:
a11 a12 … a1N
a21 a22 … a2N
……………
aN1 aN2 … aNN
b1 b2 … bN
c d
e f

g h
where aij is the transport cost from city i to city j, aij = -1 indicates there is no direct path between city i and city j. bi represents the tax of passing through city i. And the cargo is to be delivered from city c to city d, city e to city f, …, and g = h = -1. You must output the sequence of cities passed by and the total cost which is of the form:
Output

From c to d :
Path: c–>c1–>……–>ck–>d
Total cost : ……
……
From e to f :
Path: e–>e1–>……….–>ek–>f
Total cost : ……
Note: if there are more minimal paths, output the lexically smallest one. Print a blank line after each test case.
Sample Input

5 0 3 22 -1 4 3 0 5 -1 -1 22 5 0 9 20 -1 -1 9 0 4 4 -1 20 4 0 5 17 8 3 1 1 3 3 5 2 4 -1 -1 0
Sample Output

From 1 to 3 : Path: 1–>5–>4–>3 Total cost : 21 From 3 to 5 : Path: 3–>4–>5 Total cost : 16 From 2 to 4 : Path: 2–>1–>5–>4 Total cost : 17
Source

Asia 1996, Shanghai (Mainland China)

题意 给你n种币种之间的汇率关系 判断能否形成套汇现象 即某币种多次换为其它币种再换回来结果比原来多

基础的最短路 只是加号换为了乘号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
using namespace std;
map<string, int> na;
const int N = 31;
double d[N], rate[N][N], r;
int n, m, ans;

int bellman(int s)
{
memset(d, 0, sizeof(d));
d[s] = 1.0;
for(int k = 1; k <= n; ++k)
{
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
if(d[i] < d[j]*rate[j][i])
d[i] = d[j] * rate[j][i];
}
}
return d[s] > 1.0;
}

int main()
{
int cas = 0;
char s[100], a[100], b[100];
while(scanf("%d", &n), n)
{
na.clear();
ans = 0;
memset(rate, 0, sizeof(rate));
for(int i = 1; i <= n; ++i)
{
rate[i][i] = 1.0;
scanf("%s", s);
na[s] = i;
}

scanf("%d", &m);
for(int i = 1; i <= m; ++i)
{
scanf("%s%lf%s", a, &r, b);
rate[na[a]][na[b]] = r;
}

for(int i = 1; i <= n; ++i)
{
if(bellman(i))
{
ans = 1; break;
}
}
printf("Case %d: %s\n", ++cas, ans ? "Yes" : "No");
}
return 0;
}

Arbitrage

Description
Arbitrage is the use of discrepancies in currency exchange rates to transform one unit of a currency into more than one unit of the same currency. For example, suppose that 1 US Dollar buys 0.5 British pound, 1 British pound buys 10.0 French francs, and 1 French franc buys 0.21 US dollar. Then, by converting currencies, a clever trader can start with 1 US dollar and buy 0.5 /* 10.0 /* 0.21 = 1.05 US dollars, making a profit of 5 percent.
Your job is to write a program that takes a list of currency exchange rates as input and then determines whether arbitrage is possible or not.

Input

The input will contain one or more test cases. Om the first line of each test case there is an integer n (1<=n<=30), representing the number of different currencies. The next n lines each contain the name of one currency. Within a name no spaces will appear. The next line contains one integer m, representing the length of the table to follow. The last m lines each contain the name ci of a source currency, a real number rij which represents the exchange rate from ci to cj and a name cj of the destination currency. Exchanges which do not appear in the table are impossible.
Test cases are separated from each other by a blank line. Input is terminated by a value of zero (0) for n.

Output

For each test case, print one line telling whether arbitrage is possible or not in the format “Case case: Yes” respectively “Case case: No”.

Sample Input

3 USDollar BritishPound FrenchFranc 3 USDollar 0.5 BritishPound BritishPound 10.0 FrenchFranc FrenchFranc 0.21 USDollar 3 USDollar BritishPound FrenchFranc 6 USDollar 0.5 BritishPound USDollar 4.9 FrenchFranc BritishPound 10.0 FrenchFranc BritishPound 1.99 USDollar FrenchFranc 0.09 BritishPound FrenchFranc 0.19 USDollar 0

Sample Output

Case 1: Yes Case 2: No

0%