代码:
#include
#include
using namespace std;
#define endl "\n"
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t;
cin>>t;
while(t--)
{
int a,b,c,x,y,z;
cin>>a>>b>>c>>x>>y>>z;
if(a==x&&b==y&&c==z)
{
cout<<0<<endl;
continue;
}
if((a-x)%20!=0||(b-y)%20!=0||(c-z)%20!=0)
{
cout<<-1<<endl;
continue;
}
if((a+b+c)!=(x+y+z))
{
cout<<-1<<endl;
continue;
}
int ax=(a-x)/20,by=(b-y)/20,cz=(c-z)/20;
if((ax%3+3)%3!=(by%3+3)%3||(ax%3+3)%3!=(cz%3+3)%3)
{
cout<<-1<<endl;
continue;
}
7-2 拼题A打卡奖励 (25 分)
题意:
给定 N张打卡卷,第 i 张打卡卷需要 mi 分钟做完,完成后可获得 ci 枚奖励的金币。问在M 分钟内最多可以得到多少金币。
思路:
显然为01背包问题,把时间看成背包问题中的重量w,把奖励金币看成背包问题中的价值v,求在给定的w中取得的最大v。
首先分析时间复杂度,在pta中c/c++的时间限制为400ms,按照一般计算机计算的速度1s为 1 0 8 10^8 108来算的话,此题的计算量应该不能大于4× 1 0 7 10^7 107,但是按照常规的01背包来算的话,时间复杂度为O(NM)(其中N在背包问题中是物品的个数,在此题中N<= 1 0 3 10^3 103,M在背包问题中是背包的最大容积,在此题中M的范围为365×24×60,约为 1 0 5 10^5 105,于是O(NM)的时间复杂度约为 1 0 8 10^8 108,大于4× 1 0 7 10^7 107)通过分析时间复杂度得知用常规的01背包来码的话就会超时,故我们应该换一种方法。
我们再观察题目所给的其他数据,ci<30 成为题目转化的一个突破口。按照原来做法就是用最小容量求最大价值,现在反过来用最大价值求最小容量。最大价值:1000∗30, 复杂度:1000∗30∗1000为3× 1 0 7 10^7 107小于4× 1 0 7 10^7 107,故可以用该方法 。
代码:
#include
#include
#include
using namespace std;
int w[1010],v[1010];
int dp[30010];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n,m,sum=0;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>w[i];
for(int i=1;i<=n;i++)cin>>v[i],sum+=v[i];
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int i=1;i<=n;i++)
for(int j=sum;j>=v[i];j--)
dp[j]=min(dp[j],dp[j-v[i]]+w[i]);
int ans=0;
for(int i = sum; i >= 0; i--)
if(dp[i] <= m)
{
ans=i;
break;
}
cout<<ans;
return 0;
}
7-3快递装箱(25分)
题意:
具体还是直接看题目吧,我说的也不太好QAQ。一共ABCD四个口,12两缸摄像头,快递从A口开始,到B口如果是快递且重量大于W1装箱,到C口检查箱子,大于W2装车(此时1号摄像头拍摄,装车后的快递不用考虑了),其他的进入D进行装箱(分2情况,1:D空:等下一快递;2:D不空:考虑下一快递是否装得下来进行新快递装入或者装箱,如果下一是箱子或没货物,则检查重量来进行放A口或者装车(此时2号摄像头拍摄),在A口的箱子要等汇合到A的快递,如果可以装入就装入后走B,不可以就等待。
输出12摄像头拍摄次数和剩下箱子数目,并输出重量,数目如果为0的话输出None。
思路:
就是塞个货物进传送带,然后动一动,更新一下每个点的状态,如果有货物运出就答案加一。A、D 点用了双端队列处理(因为有塞回去的情况),B、C用了普通队列处理。每次更新按题目要求处理,用一个 pair 存储货物状态,分别记录重量和是否装箱。
然后塞完货物之后再让传送带动一动把一些该送走而没送走的东西处理一下,最后把传送带剩下的箱子拿出来看看。
代码来源:https://gist.github.com/dailongao/b310025a2b61b210f7822e1a3054ee8f
代码:
#include
#include
#include
#include
#include
using namespace std;
typedef pair<int, int> PII;
queue<PII> B, C, D2;
deque<PII> A, D;
int wmax, w1, w2, N;
int ans1 = 0, ans2 = 0;
vector<int> ans;
void pushA(int v) {
if(A.size() == 0) {
A.push_back(make_pair(v, 0));
} else {
PII x = A.front();
if(x.first + v <= wmax) {
A.pop_front();
A.push_front(make_pair(x.first + v, 1));
} else {
A.push_front(make_pair(v, 0));
}
}
}
void update() {
if(D.size() != 0) {
PII x = D.front();
if(x.second == 0) {
D.pop_front();
D.push_front(make_pair(x.first, 1));
} else {
D.pop_front();
if(D.size() == 0) {
D.push_front(x);
} else {
PII y = D.front();
if(y.second == 0) {
if(y.first + x.first <= wmax) {
D.pop_front();
D.push_front(make_pair(x.first + y.first, 1));
} else {
if(x.first > w2) {
ans2++;
} else {
A.push_back(x);
}
}
} else {
if(x.first > w2) {
ans2++;
} else {
A.push_back(x);
}
}
if(D.front().second == 0) {
PII z = D.front();
D.pop_front();
D.push_front(make_pair(z.first, 1));
}
}
}
}
if(C.size() != 0) {
PII x = C.front();
C.pop();
if(x.first > w2) {
ans1++;
} else {
D.push_back(x);
}
}
if(B.size() != 0) {
PII x = B.front();
B.pop();
if(x.first > w1) {
C.push(make_pair(x.first, 1));
} else {
C.push(x);
}
}
if(A.size() != 0) {
B.push(A.front());
A.pop_front();
}
}
int main() {
scanf("%d%d%d%d", &N, &wmax, &w1, &w2);
for(int i = 0; i < N; ++i) {
int x;
scanf("%d", &x);
pushA(x);
update();
}
for(int i = 0; i < 10005; ++i) {
update();
}
while(D.size() != 0) {
PII x = D.front();
D.pop_front();
if(x.first > w2)
ans2++;
else {
D2.push(x);
}
}
while(D2.size() != 0) {
D.push_back(D2.front());
D2.pop();
}
while(A.size() != 0) {
if(A.front().first != 0) ans.push_back(A.front().first);
A.pop_front();
}
while(B.size() != 0) {
if(B.front().first != 0) ans.push_back(B.front().first);
B.pop();
}
while(C.size() != 0) {
if(C.front().first != 0) ans.push_back(C.front().first);
C.pop();
}
while(D.size() != 0) {
if(D.front().first != 0) ans.push_back(D.front().first);
D.pop_front();
}
sort(ans.begin(), ans.end());
printf("%d %d %d\n", ans1, ans2, ans.size());
if(ans.size() == 0) puts("None");
else {
for(int i = 0; i < ans.size(); ++i)
printf("%d%c", ans[i], i == ans.size() - 1 ? '\n' : ' ');
}
}
7-4塔防游戏(30分)
题意:
输入n 和 m,为地图的尺寸, T,为一轮攻击持续的时长。
随后给出 n+2 行,每行给出 m+2 个数字,每行中的数字都用空格分隔,表示攻击开始前地图上的布局。其中第 1 行、第 1 列、第 n+2 行、第 m+2 列是地图边界外僵尸们出发的位置,这些位置上,0
表示没有僵尸,其他正整数表示从该位置出发的僵尸们的数量。而地图中的每个位置上,0
表示没有堡垒,其它正整数表示该位置上堡垒的防御能力值。大本营是一个负数 −D ,其防御能力值为 D。所有的僵尸队都会根据进攻开始时的地图选择被歼灭最少的到达大本营的路线,并且一直按照这个路线行进,
输出 n 行,每行 m 个数字,对应攻击结束后地图上每个方格的状态。
如果大本营被攻陷还要输出Game Over
思路:
首先因为起点不一而终点一致,我们可以做从起点出发的最短路,确定每队僵尸的行走路线。最短路因为是网格图,建议还是用带优先队列的 Dijkstra,不容易被卡复杂度(我们有空的时候会讲讲各种最短路算法的最坏情况)。
然后按照时间移动僵尸即可。我的做法是直接维护僵尸队在的位置、每次扫一次所有僵尸队伍,对于还活着的僵尸队伍,尝试向最短路路径上的下一个点移动一步,如果有堡垒挡住就打一下堡垒即可。
注意:当3个队同时攻打某个防御值为2的堡垒,该堡垒消失的同时,3个队都会减员1人,也可以理解成 ”堡垒可能减为负值“ 。最外围点(僵尸老窝)之间互不相通。
详细的还是看代码吧
代码来源:7-4 塔防游戏 (30 分)
另:https://gist.github.com/dailongao/b26364f4d6f876bdb79d1045eaf85500
代码:
#include
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef pair<int,int>PII;
typedef pair<int,PII>PIII;
struct Node{
int x , y , cc ;
};
const int N = 200;
int f[N][N];
int n,m,t;
int dx[] = {-1,1,0,0},dy[] = {0,0,-1,1};
PII e ;
vector<Node>v;
int dis[N][N];
int vis[N][N];
int tim[N][N];
PII path[N][N];
map<pair<int,int>,int>st ;
int idx = 1 ;
int cnt[N*N];
int now[N*N];
vector<PII>p[N*N];
int get(PII xx)
{
if(st.count(xx) == 0) st[xx] = idx++ ;
return st[xx] ;
}
void solve(){
scanf("%d %d %d",&n,&m,&t);
for(int i=0;i<=n+1;i++)
for(int j=0;j<=m+1;j++)
{
vis[i][j] = false;
dis[i][j] = 0x3f3f3f3f;
path[i][j] = {-1,-1};
tim[i][j] = 0 ;
scanf("%d",&f[i][j]);
if(f[i][j]<0)e = {i,j};
if((i==0&&j==m+1)||(i==0&&j==0)||(i==n+1&&j==0)||(i==n+1&&j==m+1))
continue;
if(i < 1 || i > n || j < 1 || j > m && f[i][j] > 0)
v.push_back({i,j,f[i][j]});
}
priority_queue<PIII,vector<PIII>,greater<PIII>>q;
dis[e.x][e.y] = 0;
q.push({0,{e.x,e.y}});
while(!q.empty()){
auto g = q.top();q.pop();
PII l = g.y;
if(vis[l.x][l.y])continue;
vis[l.x][l.y] = true;
for(int i=0;i<4;i++){
int a = l.x+dx[i] , b = l.y+dy[i];
if(a < 1 || a > n || b < 1 || b > m ) continue;
if(dis[a][b] > dis[l.x][l.y] + f[a][b]){
dis[a][b] = dis[l.x][l.y] + f[a][b];
path[a][b] = l;
tim[a][b] = tim[l.x][l.y]+1;
}
else if(dis[a][b]==dis[l.x][l.y]+f[a][b]){
if(tim[a][b]>tim[l.x][l.y]+1){
tim[a][b] = tim[l.x][l.y]+1;
path[a][b] = l;
}
}
q.push({dis[a][b],{a,b}});
}
}
for(auto it:v){
int id = get({it.x,it.y});
cnt[id] = it.cc ;
PII kk ;
for(int i = 0 ; i < 4 ; i++) {
if(it.x + dx[i] >= 1 && it.x + dx[i] <= n && it.y + dy[i] >= 1 && it.y + dy[i] <= m){
kk.x = it.x + dx[i] , kk.y = it.y + dy[i];
break ;
}
}
while(true){
p[id].push_back(kk);
if(kk.x==e.x && kk.y == e.y)break;
kk = path[kk.x][kk.y];
}
}
for(int i=1;i<=t;i++){
set<pair<int,int>>ss;
for(auto it:v){
int no = get({it.x,it.y});
if(cnt[no]==0)continue;
int x = p[no][now[no]].x,y = p[no][now[no]].y;
if(f[x][y] > 0 && !(x == e.x && y == e.y)){
ss.insert({x,y});
}else if(f[x][y] < 0 && (x == e.x && y == e.y)){
ss.insert({x,y});
}
}
for(auto it:v){
int no = get({it.x,it.y});
if(cnt[no]==0)continue;
int x = p[no][now[no]].x,y = p[no][now[no]].y;
if(ss.count({x,y}) == 0){
now[no] = min(now[no]+1,(int)p[no].size()-1);
}else{
if(f[x][y] > 0) f[x][y]--;
else if(f[x][y] < 0) f[x][y]++;
cnt[no]--;
}
}
if(f[e.x][e.y] == 0){
break;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%d",f[i][j]);
if(j<m)printf(" ");
}
printf("\n");
}
if(f[e.x][e.y]==0)printf("Game Over");
}
signed main() {
solve();
return 0;
}