9月4日 考试总结

时间:2022-05-08 14:38:02

1,冒泡排序
赛车比赛(race)
【题意描述】USB自己做了一辆卡丁车去参加f1 赛事,经过了一轮预选赛,还剩下 n 选手进入决赛。
由于各选手的预赛成绩不同,所以各选手的出发点si也是根据成绩而定的,
有些人的出发点不同,有些人出发点相同。每位选手根据状态还有一个保持不变
的速度vi。为了简化问题,设跑道为一条数轴,选手的坐标即为其通过距离。
排名方法如下,如果一辆车在另一辆车前面,则这辆车在另一辆车前。如果
两车的通过距离相同,则编号小的在前。USB的卡丁车是世界一流的,他不用担心当不了第一名。

他现在想知道,第t时刻排在第k 位的是那辆车。
【输入格式(race.in)
第一行,包含一个正整数n
2~n+1行,第 i+1 行包括两个正整数 visi
n+2行,包含一个正整数 m
n+3~m+2行,每行表示一个询问,包括两个正整数 t,k
【输出格式(race.out)
输出包括m行,每行表示每个询问时刻 t 排在第 k 位的选手编号。


思路:

考虑把询问按时间排序,每两个赛车之间的前后关系只会交换O(n^2)次,每次询问时把每个数向后冒泡排序,这样总复杂度O(n(n+m))。(好暴力,还是没有写出来。。。)


<span style="color:#000000;">#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;

#define MAXN (7000+5)

struct node{
	int v, s, num;
	long long dis;
	
	bool operator <(const node &x)const{
		return dis > x.dis || (dis == x.dis && num < x.num);
	}
};

struct Ask{
	int t, k, num;
	
	bool operator <(const Ask &x)const{
		return t < x.t;
	}
};

node run[MAXN];
Ask ask[MAXN];
int ans[MAXN];

int main(){
	freopen("race.in", "r", stdin);
	freopen("race.out", "w", stdout);
	
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d%d", &run[i].v, &run[i].s), run[i].num = i;
	
	int m;
	scanf("%d", &m);
	for(int i = 1; i <= m; i++) scanf("%d%d", &ask[i].t, &ask[i].k), ask[i].num = i;
	sort(ask+1, ask+m+1);
	
	int ft = ask[1].t;
	for(int i = 1; i <= n; i++) run[i].dis = 1LL * run[i].v * ft + run[i].s;
	sort(run+1, run+n+1);
	
	ans[ask[1].num] = run[ask[1].k].num;
	for(int ca = 2; ca <= m; ca++){
		for(int i = 1; i <= n; i++) run[i].dis = 1LL * run[i].v * ask[ca].t + run[i].s;
		
		for(int i = 2; i <= n; i++){
			int t = i;
			while(t > 1 && run[t] < run[t-1]) swap(run[t], run[t-1]), t--;
		}
		ans[ask[ca].num] = run[ask[ca].k].num;
	}
	for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
	
	return 0;
}</span>

2.DP

物流运输(trans)
物流公司要把一批货物从码头A运到码头 B。由于货物量比较大,需要n
才能运完。货物运输过程中一般要转停好几个码头。物流公司通常会设计一条固
定的运输路线,以便对整个运输过程实施严格的管理和跟踪。由于各种因素的存
在,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能
够按时到达目的地。但是修改路线是一件十分麻烦的事情,会带来额外的成本。
因此物流公司希望能够订一个n天的运输计划,使得总成本尽可能地小。
【输入格式(trans.in)
文件trans.in的第一行是四个整数 n 1<=n<=100)、m 1<=m<=20)、K e

n表示货物运输所需天数,m表示码头总数,K表示每次修改运输路线所需成本。
接下来e行每行是一条航线᧿述,包括了三个整数,依次表示航线连接的两个码
头编号以及航线长度(>0)。其中码头A编号为 1,码头B编号为 m。单位长度
的运输费用为1。航线是双向的。
再接下来一行是一个整数d,后面的d行每行是三个整数 P1<P<m)、ab
1<=a<=b<=n)。表示编号为P的码头从第 a 天到第 b 天无法装卸货物(含头尾)。
同一个码头有可能在多个时间段内不可用。但任何时间都存在至少一条从码头A
到码头B的运输路线。
保证数据有梯度。
【输出格式(trans.out)
文件trans.out包括了一个整数表示最小的总成本。总成本=n天运输路线长度之
+K*改变运输路线的次数。
【样例输入】

5 5 10 8
1 2 1
1 3 3
1 4 2
2 3 2
2 4 4
3 4 1
3 5 2
4 5 2
4
2 2 3
3 1 1
3 3 3
4 4 5

【样例输出】32


思路:

令dp[i]为前i天的最小花费,枚举最后一次的航线改变时间j。用最短路算出满足从第j天到第i天的最短航线。复杂度O(n^2elogn)。(我想到了是DP,但是。。。没写出来)

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

using namespace std;

#define MAXN (100+5)
#define MAXM (20+5)
#define INF 0x3f3f3f3f

struct node{
	int v, dis;
	
	bool operator <(const node &x)const{
		return dis < x.dis;
	}
};

int n, m, rk, e;
int G[MAXN][MAXN], dp[MAXN], dist[MAXN];
bool flag[MAXN], vis[MAXN], f[MAXN][MAXM];

int main(){
	freopen("trans.in", "r", stdin);
	freopen("trans.out", "w", stdout);
	
	scanf("%d%d%d%d", &n, &m, &rk, &e);
	
	for(int i = 1; i <= e; i++){
		int u, v, dis;
		scanf("%d%d%d", &u, &v, &dis);	
		G[u][v] = G[v][u] = dis;
	}
	
	int D;
	scanf("%d", &D);
	
	memset(f, true, sizeof(f));
	for(int i = 1; i <= D; i++){
		int p, l, r;
		scanf("%d%d%d", &p, &l, &r);
		for(int j = l; j <= r; j++) f[j][p] = false;
	}
	
	memset(dp, 0x3f, sizeof(dp));
	dp[0] = -rk;
	for(int i = 1; i <= n; i++){
		memset(flag, true, sizeof(flag));
		
		for(int j = i-1; j >= 0; j--){
			for(int k = 1; k <= m; k++) flag[k] = flag[k] && f[j+1][k], dist[k] = INF;
			memset(vis, true, sizeof(vis));
			
			int u = 1;
			dist[1] = 0;
			while(u){
				vis[u] = false;
				for(int k = 1; k <= m; k++)
				  if(flag[k] && G[u][k] && (dist[u]+G[u][k] < dist[k])) dist[k] = dist[u] + G[u][k]; 
				
				u = 0;
				for(int k = 1; k <= m; k++)
				    if(dist[k] && vis[k] && (!u || (dist[u] > dist[k]))) u = k;
			}
			
			if(dist[m] == INF) continue;
		 	dp[i] = min(dp[i], dp[j]+rk+dist[m]*(i-j));
		}
	}
	printf("%d\n", dp[n]);
	
	return 0;
}


莫名想吐槽4个月前的自己->_->:

1.这种水题怎么想不到。

2.然后,代码以前肯定抄的标程

3.并且,这文章的排版当时怎么看下去的???

(2017.2.5)今天的我才发现这是ZJOI2006的原水题,然而重写了一遍,贴贴代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;

#define LL long long
#define Set(a, v) memset(a, v, sizeof(a))
#define For(i, a, b) for(int i = (a); i <= (int)(b); i++)

#define N (100+5)
#define M (20+5)
#define INF 0x3f3f3f3f

void read(int &x){
    char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    x = 0;
    while(ch >= '0' && ch <= '9'){
        x = x*10+ch-'0';
        ch = getchar();
    }
}

LL f[N];
int n, m, tl, tr, now, G[M][M], d[M];
bool stop[N][M], use[M], inq[M];

inline int spfa(){
	For(i, 1, m){
		use[i] = true;
		For(j, tl, tr) if(stop[j][i]){use[i] = false; break;}
	}
	if(!use[1]) return INF;

	Set(d, INF); Set(inq, 0);
	d[1] = 0; inq[1] = true;
	queue<int> q; q.push(1);
	while(!q.empty()){
		now = q.front(); q.pop();
		inq[now] = false;

		For(v, 1, m){
			if(!use[v] || G[now][v]==0) continue;		
			if(d[v] > (d[now]+G[now][v])){
				d[v] = d[now]+G[now][v];
				if(!inq[v]){q.push(v); inq[v] = true;}
			}
		}
	}
	return d[m];
}

int main(){
	int k, E, rd, u, v, w, p, a, b;
        read(n); read(m); read(k); read(E);
	For(i, 1, E){
        read(u); read(v); read(w);
		if(!G[u][v]) G[u][v] = G[v][u] = w;
		else G[u][v] = G[v][u] = min(G[u][v], w);
	}
        read(rd);
	while(rd--){
        read(p); read(a); read(b);
		For(i, a, b) stop[i][p] = true;
	}

	tl = tr = 1; f[1] = spfa();
	For(i, 2, n){
		tl = 1; tr = i; f[i] = 1LL*spfa()*i;

		For(j, 1, i-1){
			tl = j+1;
			f[i] = min(f[i], f[j]+1LL*spfa()*(i-j)+k);
		}
	}
	printf("%lld\n", f[n]);

	return 0;
}