0930上午考试
0930上午考试
T1
题目大意:
Nescafe之塔一共有N层,升降梯在每层都有一个停靠点。手柄有M个控制槽,第i个控制槽旁边标着一个数Ci,满足C1<C2<C3<......<CM。如果Ci>0,表示手柄扳动到该槽时,电梯将上升Ci层;如果Ci<0,表示手柄扳动到该槽时,电梯将下降-Ci层;并且一定存在一个Ci=0,手柄最初就位于此槽中。注意升降梯只能在1~N层间移动,因此扳动到使升降梯移动到1层以下、N层以上的控制槽是不允许的。电梯每移动一层,需要花费2秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费1秒钟时间。探险队员现在在1层,并且想尽快到达N层,他们想知道从1层到N层至少需要多长时间?如果到不了就输出-1
对于100%的数据,满足1≤N≤1000,2<=M<=20,-N<C1<C2<......<CM<N。
好吧这道题我是完全不会。
正解最短路,把现在在某一层,某个手柄作为状态,把手柄和升降梯的移动看做边,但是不用建边,思路还是很巧妙的。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int M = 21, N = 1005, inf = 1e9;
int n, m, z, ans;
int a[N], vis[N][M], dis[N][M];
struct node {
int dis, x, y;
node() {}
node(int D, int X, int Y) { dis = D, x = X, y = Y; }
friend operator > (const node &a, const node &b) { return a.dis > b.dis; }
} ;
void ran_dij() {
for(int i = 1;i <= n; i++)
for(int j = 1;j <= m; j++) dis[i][j] = inf;
priority_queue <node, vector<node>, greater<node> > q;
q.push(node(0, 1, z)); dis[1][z] = 0;
while(!q.empty()) {
int x = q.top().x, y = q.top().y; q.pop();
if(vis[x][y]) continue; vis[x][y] = 1;
if(y != 1) {
int nowy = y - 1;
if(dis[x][nowy] > dis[x][y] + 1) {
dis[x][nowy] = dis[x][y] + 1;
q.push(node(dis[x][nowy], x, nowy));
}
}
if(y != m) {
int nowy = y + 1;
if(dis[x][nowy] > dis[x][y] + 1) {
dis[x][nowy] = dis[x][y] + 1;
q.push(node(dis[x][nowy], x, nowy));
}
}
int nowx = x + a[y];
if(nowx >= 1 && nowx <= n) {
if(dis[nowx][y] > dis[x][y] + 2 * abs(a[y])) {
dis[nowx][y] = dis[x][y] + 2 * abs(a[y]);
q.push(node(dis[nowx][y], nowx, y));
}
}
}
}
int main() {
n = read(); m = read();
for(int i = 1;i <= m; i++) {
a[i] = read(); if(a[i] == 0) z = i;
}
ran_dij(); ans = inf;
for(int i = 1;i <= m; i++) ans = min(ans, dis[n][i]);
printf("%d", ans == inf ? -1 : ans);
fclose(stdin); fclose(stdout);
return 0;
}
T2
题目大意:
王伯(不是王婆)退休后开始养鱼。他一早起床就赶去动物园,发现这个世界的鱼真不少,五光十色、色彩斑斓,大的、小的,什么都有。这些鱼实在是太美了,买的人越来越多,湖里的鱼越来越少。没有美丽的鱼哪里有美丽的湖?于是动物园不得不规定,对于每种鱼,每个人最多可以买一条。并且有些鱼不能一起买的,因为它们之间会相互争斗吞食。王伯想买尽可能多的鱼,但很可惜,他的资金有限。他冥想苦思,不知道如何是好。请编写一个程序帮助他。如果有多个方案都能买尽可能多的鱼,选择所花资金最多的一个。
【输出格式】第一行为两个正整数X,Y,分别表示所买的鱼的条数和总花费。以下X行,每行有一个正整数,表示所买的鱼的编号。编号按升序排列输出。如果题目有多个解,输出其中字典序最小的一个。
刚刚看题,二分图???又看了一会儿,二进制,绝对二进制。写了一个小时后,md写挂了,不能用二进制。算了写个迭代加深吧,20pts……(我吐了)
正解是搜索,用到了xjb算法。????? 注意下剪枝就好了,细节还挺多的,刚开始以为编号没啥用,其实必须带上编号,还是得好好审题呀。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 40;
int m, n, ans_sum, ans_cnt, id[N], getid[N], vis[N], tmp[N], ans[N];
struct node { int id, x; } a[N];
vector <int> v[N];
int cmp(node a, node b) { return a.id < b.id; }
void dfs(int now, int cnt, int sum) {
if(cnt + n - now + 1 < ans_cnt) return ; //如果无法更新已有最优解就返回
if(sum > m) return ; //如果王伯破产了就返回
if(now == n + 1) {
if(cnt > ans_cnt || (cnt == ans_cnt && sum > ans_sum)) { //这是更新答案的条件
for(int i = 1;i <= n; i++) ans[i] = tmp[i];
ans_cnt = cnt; ans_sum = sum;
}
return ;
}
if(!vis[now]) {
tmp[now] = 1;
for(int i = 0;i < (int)v[now].size(); i++) vis[v[now][i]] ++; //注意这里写自加或自减,不可直接赋为0或1
dfs(now + 1, cnt + 1, sum + a[now].x);
tmp[now] = 0;
for(int i = 0;i < (int)v[now].size(); i++) vis[v[now][i]] --;
}
dfs(now + 1, cnt, sum);
}
int main() {
m = read(); n = read();
for(int i = 1;i <= n; i++)
a[i].id = read(), a[i].x = read();
sort(a + 1, a + n + 1, cmp);
for(int i = 1;i <= n; i++) getid[a[i].id] = i;
while(666666) {
int x = read(), y = read(); if(x == 0 && y == 0) break;
x = getid[x], y = getid[y];
v[x].push_back(y); v[y].push_back(x);
}
dfs(1, 0, 0);
printf("%d %d\n", ans_cnt, ans_sum);
for(int i = 1;i <= n; i++)
if(ans[i]) printf("%d\n", a[i].id);
fclose(stdin); fclose(stdout);
return 0;
}
T3
题目大意:
Freda和rainbow饲养了N只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了。Freda和rainbow只好花钱让它们坐索道下山。索道上的缆车最大承重量为W,而N只小猫的重量分别是C1、C2......CN。当然,每辆缆车上的小猫的重量之和不能超过W。每租用一辆缆车,Freda和rainbow就要付1美元,所以他们想知道,最少需要付多少美元才能把这N只小猫都运送下山?
考试时想的是贪心,但是贪心写炸了,从80pts -> 20pts。QWQ
贪心的做法是按重量排序,先放大的再放小的,但是不对,比如这组数据:
6 50
20 20 15 15 15 15
正解为2:{20, 15, 15}, {20, 15, 15};
贪心为3:{20, 20}, {15, 15, 15}, {15}。
所以还是写搜索了。我们搜到每一个小猫是都分两种情况:让它自己坐一辆,让它和别的猫挤一辆。加点优化:如果当前搜到的车的数量大于等于现有最大值,那么一定更新不了答案,直接返回;我们把猫从大到小排个序,因为大猫一定会比小猫更难放。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 20;
int n, w, cnt, ans, a[N], tmp[N];
int cmp(int a, int b) { return a > b; }
void dfs(int now_cnt, int now) {
if(now_cnt >= ans) return ;
if(now == n + 1) { ans = min(ans, now_cnt); return ; }
for(int i = 1;i <= cnt; i++) {
if(tmp[i] >= a[now]) tmp[i] -= a[now], dfs(now_cnt, now + 1), tmp[i] += a[now];
}
tmp[++cnt] = w - a[now];
dfs(now_cnt + 1, now + 1);
cnt --;
}
int main() {
n = read(); w = read(); ans = 100;
for(int i = 1;i <= n; i++) a[i] = read();
sort(a + 1, a + n + 1, cmp);
dfs(0, 1); //缩索
printf("%d", ans);
fclose(stdin); fclose(stdout);
return 0;
}