我是个没有感情的WA题机
(一)最短路
谢天谢地终于有个能码题的专题了(暴风哭泣)
A - 最短路
题目描述
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
Sample Output
3
2
理解
用五种方法来做,分别是:
1)DFS 2)Floyd 3)Bellmanford 4)Dijkstra 5)SPFA
AC代码
DFS
#include<bits/stdc++.h>
using namespace std;
int mp[105][105];
bool v[105];
int n,m;
int minx;
void dfs(int now,int sum){
if(sum > minx) return;
if(now == n){
if(sum < minx) minx = sum;
return;
}
for(int i = 1;i <= n;i++){
if(!v[i] && mp[now][i]){
v[i] = 1;
dfs(i,sum + mp[now][i]);
v[i] = 0;
}
}
return;
}
int main(){
while(~scanf("%d %d",&n,&m)){
if(n == 0 && m == 0) break;
memset(mp,0,sizeof(mp));
memset(v,0,sizeof(v));
for(int i = 0;i < m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
mp[a][b] = mp[b][a] = c;
}
minx = 0x3f3f3f;
dfs(1,0);
cout << minx << endl;
}
return 0;
}
Floyd
#include<bits/stdc++.h>
using namespace std;
int dis[105][105];
int n,m;
void floyd(){
for(int k = 1;k <= n;k++){
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
}
int main(){
while(~scanf("%d %d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= i;j++){
if(i == j) dis[i][j] = 0;
else dis[i][j] = dis[j][i] = 0x3f3f3f;
}
}
for(int i = 1;i <= m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
dis[a][b] = dis[b][a] = c;
}
floyd();
printf("%d\n",dis[1][n]);
}
return 0;
}
Bellmanford
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f;
struct node{
int st,en,cost;
}ga[10005];
int dis[105];
void bellman(int n,int m){
memset(dis,inf,sizeof(dis));
dis[1] = 0;
for(int i = 2;i <= n;i++)
for(int j = 1;j <= m;j++){
if(dis[ga[j].en] > dis[ga[j].st] + ga[j].cost)
dis[ga[j].en] = dis[ga[j].st] + ga[j].cost;
if(dis[ga[j].st] > dis[ga[j].en] + ga[j].cost)
dis[ga[j].st] = dis[ga[j].en] + ga[j].cost;
}
}
int main(){
int n,m;
while(~scanf("%d %d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 1;i <= m;i++){
scanf("%d %d %d",&ga[i].st,&ga[i].en,&ga[i].cost);
}
bellman(n,m);
printf("%d\n",dis[n]);
}
return 0;
}
Dijkstra
#include<bits/stdc++.h>
using namespace std;
int mp[105][105];
int dis[105] = {0},v[105] = {0};
void dijkstra(int n,int x){
int minx,y;
for(int i = 1;i <= n;i++){
dis[i] = mp[x][i];
v[i] = 0;
}
v[x] = 1;
for(int i = 1;i < n;i++){
minx = 0x3f3f3f;
y = -1;
for(int j = 1;j <= n;j++){
if(!v[j] && dis[j] < minx){
y = j;
minx = dis[j];
}
}
v[y] = 1;
for(int j = 1;j <= n;j++)
if(!v[j])
if(dis[y] + mp[y][j] < dis[j] && mp[y][j] < 0x3f3f3f)
dis[j] = dis[y] + mp[y][j];
}
}
int main(){
int n,m;
while(~scanf("%d %d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
mp[i][j] = 0x3f3f3f;
}
}
for(int i = 0;i < m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
mp[a][b] = mp[b][a] = c;
}
dijkstra(n,1);
printf("%d\n",dis[n]);
}
return 0;
}
SPFA
#include<bits/stdc++.h>
using namespace std;
int mp[105][105];
int dis[105],v[105];
int n,m;
void spfa(int x){
for(int i = 1;i <= n;i++){
dis[i] = 0x3f3f3f;
v[i] = 0;
}
dis[x] = 0;
queue<int> q;
q.push(x);
v[x] = 1;
while(!q.empty()){
int now = q.front();
q.pop();
v[now] = 0;
for(int i = 1;i <= n;i++){
if(dis[i] > dis[now] + mp[now][i]){
dis[i] = dis[now] + mp[now][i];
if(v[i] == 0){
q.push(i);
v[i] = 1;
}
}
}
}
}
int main(){
while(~scanf("%d %d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= i;j++){
if(i == j) mp[i][j] = 0;
else mp[i][j] = mp[j][i] = 0x3f3f3f;
}
}
for(int i = 1;i <= m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
mp[a][b] = mp[b][a] = c;
}
spfa(1);
printf("%d\n",dis[n]);
}
return 0;
}
B - Shortest Path
题目描述
When YY was a boy and LMY was a girl, they trained for NOI (National Olympiad in Informatics) in GD team. One day, GD team’s coach, Prof. GUO asked them to solve the following shortest-path problem.
There is a weighted directed multigraph G. And there are following two operations for the weighted directed multigraph:
(1) Mark a vertex in the graph.
(2) Find the shortest-path between two vertices only through marked vertices.
For it was the first time that LMY faced such a problem, she was very nervous. At this moment, YY decided to help LMY to analyze the shortest-path problem. With the help of YY, LMY solved the problem at once, admiring YY very much. Since then, when LMY meets problems, she always calls YY to analyze the problems for her. Of course, YY is very glad to help LMY. Finally, it is known to us all, YY and LMY become programming lovers.
Could you also solve the shortest-path problem?
Input
The input consists of multiple test cases. For each test case, the first line contains three integers N, M and Q, where N is the number of vertices in the given graph, N≤300; M is the number of arcs, M≤100000; and Q is the number of operations, Q ≤100000. All vertices are number as 0, 1, 2, … , N - 1, respectively. Initially all vertices are unmarked. Each of the next M lines describes an arc by three integers (x, y, c): initial vertex (x), terminal vertex (y), and the weight of the arc ©. (c > 0) Then each of the next Q lines describes an operation, where operation “0 x” represents that vertex x is marked, and operation “1 x y” finds the length of shortest-path between x and y only through marked vertices. There is a blank line between two consecutive test cases.
End of input is indicated by a line containing N = M = Q = 0.
Output
Start each test case with “Case #:” on a single line, where # is the case number starting from 1.
For operation “0 x”, if vertex x has been marked, output “ERROR! At point x”.
For operation “1 x y”, if vertex x or vertex y isn’t marked, output “ERROR! At path x to y”; if y isn’t reachable from x through marked vertices, output “No such path”; otherwise output the length of the shortest-path. The format is showed as sample output.
There is a blank line between two consecutive test cases.
Sample Input
5 10 10
1 2 6335
0 4 5725
3 3 6963
4 0 8146
1 2 9962
1 0 1943
2 1 2392
4 2 154
2 2 7422
1 3 9896
0 1
0 3
0 2
0 4
0 4
0 1
1 3 3
1 1 1
0 3
0 4
0 0 0
Sample Output
Case 1:
ERROR! At point 4
ERROR! At point 1
0
0
ERROR! At point 3
ERROR! At point 4
AC代码
#include<bits/stdc++.h>
using namespace std;
int mp[305][305];
int vis[305];
int inf = 0x3f3f3f;
int n,m,q;
void floyd(int k){
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
if(mp[i][j] > mp[i][k] + mp[k][j])
mp[i][j] = mp[i][k] + mp[k][j];
}
int main(){
int cas = 1;
while(scanf("%d %d %d",&n,&m,&q)){
if(n == 0 && m == 0 && q == 0) break;
memset(vis,0,sizeof(vis));
for(int i = 0;i <= n;i++){
for(int j = 0;j <= n;j++)
mp[i][j] = inf;
mp[i][i] = 0;
}
for(int i = 0;i < m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
if(c < mp[a][b]){
mp[a][b] = c;
}
}
if(cas != 1) printf("\n");
printf("Case %d:\n",cas++);
for(int i = 0;i < q;i++){
int t; scanf("%d",&t);
if(t){
int x,y; scanf("%d %d",&x,&y);
if(vis[x] && vis[y]){
if(mp[x][y] != inf)
printf("%d\n",mp[x][y]);
else printf("No such path\n");
}
else{
printf("ERROR! At path %d to %d\n",x,y);
}
}
else{
int x; scanf("%d",&x);
if(vis[x]) printf("ERROR! At point %d\n",x);
else{
vis[x] = 1;
floyd(x);
}
}
}
}
return 0;
}
C - Currency Exchange
题目描述
Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several points specializing in the same pair of currencies. Each point has its own exchange rates, exchange rate of A to B is the quantity of B you get for 1A. Also each exchange point has some commission, the sum you have to pay for your exchange operation. Commission is always collected in source currency.
For example, if you want to exchange 100 US Dollars into Russian Rubles at the exchange point, where the exchange rate is 29.75, and the commission is 0.39 you will get (100 - 0.39) * 29.75 = 2963.3975RUR.
You surely know that there are N different currencies you can deal with in our city. Let us assign unique integer number from 1 to N to each currency. Then each exchange point can be described with 6 numbers: integer A and B - numbers of currencies it exchanges, and real R AB, C AB, R BA and C BA - exchange rates and commissions when exchanging A to B and B to A respectively.
Nick has some money in currency S and wonders if he can somehow, after some exchange operations, increase his capital. Of course, he wants to have his money in currency S in the end. Help him to answer this difficult question. Nick must always have non-negative sum of money while making his operations.
Input
The first line of the input contains four numbers: N - the number of currencies, M - the number of exchange points, S - the number of currency Nick has and V - the quantity of currency units he has. The following M lines contain 6 numbers each - the description of the corresponding exchange point - in specified above order. Numbers are separated by one or more spaces. 1<=S<=N<=100, 1<=M<=100, V is real number, 0<=V<=10 3.
For each point exchange rates and commissions are real, given with at most two digits after the decimal point, 10 -2<=rate<=10 2, 0<=commission<=10 2.
Let us call some sequence of the exchange operations simple if no exchange point is used more than once in this sequence. You may assume that ratio of the numeric values of the sums at the end and at the beginning of any simple sequence of the exchange operations will be less than 10 4.
Output
If Nick can increase his wealth, output YES, in other case output NO to the output file.
Sample Input
3 2 1 20.0
1 2 1.00 1.00 1.00 1.00
2 3 1.10 1.00 1.10 1.00
Sample Output
YES
AC代码
#include<iostream>
#include <cstdio>
#include<algorithm>
#include <cstring>
using namespace std;
int n,m,s;
double v;
double mp1[105][105]={0},mp2[105][105]={0},mmp[105]={0};
int floyd(){
double temp[105];
for(int i = 1;i <= n;i++) temp[i] = mmp[i];
for(int k = 1;k <= n;k++)
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
if((mmp[i] - mp2[i][j])*mp1[i][j] > mmp[j]) mmp[j] = (mmp[i] - mp2[i][j])*mp1[i][j];
for(int i = 1;i <= n;i++)
if(temp[i] < mmp[i]) return 1;
return 0;
}
int main(){
cin >> n >> m >> s >> v;
for(int i = 1;i <= m;i++){
int a,b; double c,d,e,f;
cin >> a >> b >> c >> d >> e >> f;
mp1[a][b] = c; mp2[a][b] = d;
mp1[b][a] = e; mp2[b][a] = f;
}
mmp[s] = v;
floyd();
if(floyd()) cout<<"YES\n";
else cout<<"NO\n";
}
(二)线段树
A - I Hate It
题目描述
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
Input
本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。
当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output
对于每一次询问操作,在一行里面输出最高成绩。
Sample Input
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5
Sample Output
5
6
5
9
Hint
Huge input,the C function scanf() will work better than cin
AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int m,n;
struct node{
int l,r,sum,mx;
}tree[maxn*4];
void build(int l,int r,int t){
tree[t].l = l;
tree[t].r = r;
tree[t].sum = tree[t].mx = 0;
if(l == r){
scanf("%d",&tree[t].sum);
tree[t].mx = tree[t].sum;
return;
}
int mid = (l + r) / 2;
build(l,mid,t*2);
build(mid+1,r,t*2+1);
tree[t].mx = max(tree[t*2].mx,tree[t*2+1].mx);
}
void change(int k,int val,int t){
if(tree[t].l == tree[t].r){
tree[t].mx = val;
return;
}
int mid = (tree[t].l + tree[t].r) / 2;
if(k <= mid){
change(k,val,t*2);
}
else{
change(k,val,t*2+1);
}
tree[t].mx = max(tree[t*2].mx,tree[t*2+1].mx);
}
int find_k(int l,int r,int t){
if(l == tree[t].l && r == tree[t].r){
return tree[t].mx;
}
int mid = (tree[t].l + tree[t].r) / 2;
if(r <= mid){
find_k(l,r,t*2);
}
else if(l > mid){
find_k(l,r,t*2+1);
}
else{
return max(find_k(l,mid,t*2),find_k(mid+1,r,t * 2 + 1));
}
}
int main(){
while(~scanf("%d %d",&n,&m)){
build(1,n,1);
while(m--){
char c;
cin >> c;
if(c == 'Q'){
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",find_k(l,r,1));
}
else{
int k,val;
scanf("%d %d",&k,&val);
change(k,val,1);
}
}
}
return 0;
}
(三)我的感想
question:!为什么线段树要开四倍的空间!
看看代佬们的博客貌似稍微懂了一些ummm,具体也解释不来
关于本周,也没有经常刷题,回家玩了一趟,也就最短路的题目能用dfs和floyd水一水,线段树这个原理大概是懂了的,就是写题目时板子敲敲改改还是用起来挺复杂的,老是出错,,,果然还是得多练练。