1,冒泡排序
赛车比赛(race)
【题意描述】USB自己做了一辆卡丁车去参加f1 赛事,经过了一轮预选赛,还剩下 n 名选手进入决赛。
由于各选手的预赛成绩不同,所以各选手的出发点si也是根据成绩而定的,
有些人的出发点不同,有些人出发点相同。每位选手根据状态还有一个保持不变
的速度vi。为了简化问题,设跑道为一条数轴,选手的坐标即为其通过距离。
排名方法如下,如果一辆车在另一辆车前面,则这辆车在另一辆车前。如果
两车的通过距离相同,则编号小的在前。USB的卡丁车是世界一流的,他不用担心当不了第一名。
他现在想知道,第t时刻排在第k 位的是那辆车。
【输入格式(race.in)】
第一行,包含一个正整数n。
第2~n+1行,第 i+1 行包括两个正整数 vi,si。
第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行每行是三个整数 P(1<P<m)、a、b
(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;
}