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; }