A 張老師和菜哭武的遊戲
題目中有描述“當且僅當集合存在y和z,滿足x等於y+z或者y-z”
所以考慮y-z,很容易想到輾轉相減法,所以最小項是最大公約數
然後題目就迎刃而解了
#include <bits/stdc++.h>
using namespace std;
int n,a,b;
int gcd(int a,int b){
if(a==b)return a;
return a>b?gcd(a-b,b):gcd(b-a,a);
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>a>>b;
int temp=gcd(a,b);
int ans=n/temp;
if(ans%2==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}
B 傷害計算
看了題解,覺得還是用atoi更加簡單;
atoi主要用來將數字字符串轉變爲對應的整型數字,具體用法網上教程很多;
數學期望的計算公式是用各項權值乘以概率,常數的數學期望就是常數,公式推導還是挺簡單的;
注意題目中小數只有.5,所以方便計算,可以將各項結果先乘以2,最後除2,看餘數決定是否輸出.5;
ps:字符串題目多用函數可以減少很多時間;
#include <bits/stdc++.h>
using namespace std;
const int MAXL=6000;
char strfuc[MAXL];
int ans;
void opera(char *str){
char *D=strchr(str,'d');
if(D==NULL){
int c=atoi(str);
ans+=2*c;
//cout<<c<<endl;
}else{
*D='\0';
int n=atoi(str);
int x=atoi(D+1);
ans+=n*(x+1);
//cout<<n<<" "<<x<<endl;
}
}
int main(){
while(cin>>strfuc){
ans=0;
char* str=strfuc;
while(1){
char* ps=strchr(str,'+');
if(ps==NULL){
opera(str);
break;
}else{
*ps='\0';
opera(str);
str=ps+1;
}
}
cout<<ans/2;
if(ans%2) cout<<".5"<<endl;
else cout<<endl;
}
return 0;
}
C 張老師的旅行
直覺上感覺可以用貪心去做;
結果wa了;
仔細想想還是不行,跟任務分配問題還是有區別的;
這道題dp還是比較難想的;
通俗的講:
比如你在起點位置,你左邊有i個景點,右邊有j個景點,問題就是問你瀏覽完所有景點的最小時間;
首先你不管以什麼順序瀏覽,你要麼最後停在i點,要麼最後停在j點;
所以要分兩種情況來討論;
以最後停在i點爲例;
這個問題的子問題,比如瀏覽完左邊的i-1個景點,右邊的j個景點的最短時間已經求得;
那麼對於子問題兩種情況的可行解(一種停在i-1點,一種停在j點),你都要回到i點,那麼加上對應的路程就可以了(想象你從i-1出發走到i,或從j出發走到i);
然後問題的解就是兩種情況的最小的那一個;
然後ac的代碼;
#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f;
struct point{
int deadline;
int coordinate;
};
point mp[1100];
point leftpointSet[1100];
point rightpointSet[1100];
int dp[1100][1100][2];
bool cmp(point a,point b){
return a.coordinate<b.coordinate;
}
int main(){
int n;
cin>>n;
int my_coordinate;
for(int i=1;i<=n;i++){
cin>>mp[i].coordinate;
}
for(int i=1;i<=n;i++){
cin>>mp[i].deadline;
if(mp[i].deadline==0) my_coordinate=i;
}
sort(mp+1,mp+1+n,cmp);
memset(dp,INF,sizeof(dp));
dp[0][0][1]=0;
dp[0][0][0]=0;
int cnt_left=0,cnt_right=0;
for(int i=my_coordinate-1;i>0;i--){
cnt_left++;
leftpointSet[cnt_left].coordinate=abs(mp[i].coordinate-mp[my_coordinate].coordinate);
leftpointSet[cnt_left].deadline=mp[i].deadline;
}
for(int i=my_coordinate+1;i<=n;i++){
cnt_right++;
rightpointSet[cnt_right].coordinate=abs(mp[i].coordinate-mp[my_coordinate].coordinate);
rightpointSet[cnt_right].deadline=mp[i].deadline;
}
/*
cout<<my_coordinate<<endl;
for(int i=1;i<=cnt_left;i++) cout<<leftpointSet[i].coordinate<<" ";
cout<<endl;
for(int j=1;j<=cnt_right;j++) cout<<rightpointSet[j].coordinate<<" ";
cout<<endl;
*/
for(int i=0;i<=cnt_left;i++){
for(int j=0;j<=cnt_right;j++){
if(i){
dp[i][j][0]=min(dp[i-1][j][0]-leftpointSet[i-1].coordinate+leftpointSet[i].coordinate,dp[i-1][j][1]+rightpointSet[j].coordinate+leftpointSet[i].coordinate);
}
if(j){
dp[i][j][1]=min(dp[i][j-1][1]-rightpointSet[j-1].coordinate+rightpointSet[j].coordinate,dp[i][j-1][0]+leftpointSet[i].coordinate+rightpointSet[j].coordinate);
}
if(dp[i][j][0]>leftpointSet[i].deadline && dp[i][j][1]>rightpointSet[j].deadline){
cout<<-1<<endl;
return 0;
}
if(dp[i][j][0]>leftpointSet[i].deadline) dp[i][j][0]=INF;
if(dp[i][j][1]>rightpointSet[j].deadline) dp[i][j][1]=INF;
}
}
cout<<min(dp[cnt_left][cnt_right][0],dp[cnt_left][cnt_right][1])<<endl;
return 0;
}
D 車輛調度
注意車一次可以走到頭,同時不止一輛車,也不止一個終點;
這樣就要考慮車不僅會在遇到障礙物的情況下停下,也有可能在遇到車的時候停下,這時候僅僅把車的位置作爲bfs時的結點就不行了;
其實這種問題,非常像一種叫華容道的傳統遊戲;
因爲此時你上一步操作會影響下一步操作,這種情況下,一般可以將圖作爲bfs的結點,這樣每一個節點都是起點圖可能到達的一種情況,然後去找符合題目要求的圖就可以了;
因爲圖有可能重複,可以用一個set來去掉重複的圖(剪枝),同時因爲k已經給了,所以如果操作步驟超過了k,就可以輸出no,不需要再操作了;
ps:給出一道類似的題:Rush Hour Puzzle 有興趣可以做一下
代碼中的註釋去掉,可以瀏覽所有結點;
ac代碼:
#include <bits/stdc++.h>
#define P pair<int,int>
using namespace std;
int h,w;
int k;
struct mp{
char p[15][15];
bool friend operator<(const mp &a,const mp &b){
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
if(a.p[i][j]!=b.p[i][j]) return a.p[i][j]<b.p[i][j];
}
}
return false;
}
};
struct node{
P car[8];
P goal[100];
int cnt;
mp p;
}c;
set <mp> st;
queue <node> q;
bool ans=false;
bool move(node &res,int id,int de){
mp &p=res.p;
P &car=res.car[id];
int h1,w1;
h1=car.first;
w1=car.second;
if(de==1){
int temp=w;
if(car.second==w) return false;
for(int i=w1+1;i<=w;i++){
if(p.p[h1][i]=='R' || p.p[h1][i]=='X'){
temp=i-1;
break;
}
}
p.p[car.first][car.second]='.';
car.first=h1;
car.second=temp;
p.p[car.first][car.second]='R';
}
if(de==2){
int temp=1;
if(car.second==1) return false;
for(int i=w1-1;i>=1;i--){
if(p.p[h1][i]=='R' || p.p[h1][i]=='X'){
temp=i+1;
break;
}
}
p.p[car.first][car.second]='.';
car.first=h1;
car.second=temp;
p.p[car.first][car.second]='R';
}
if(de==3){
int temp=h;
if(car.first==h) return false;
for(int i=h1+1;i<=h;i++){
if(p.p[i][w1]=='R' || p.p[i][w1]=='X'){
temp=i-1;
break;
}
}
p.p[car.first][car.second]='.';
car.first=temp;
car.second=w1;
p.p[car.first][car.second]='R';
}
if(de==4){
int temp=1;
if(car.first==1) return false;
for(int i=h1-1;i>=1;i--){
if(p.p[i][w1]=='R' || p.p[i][w1]=='X'){
temp=i+1;
break;
}
}
p.p[car.first][car.second]='.';
car.first=temp;
car.second=w1;
p.p[car.first][car.second]='R';
}
/*
cout<<res.cnt<<endl;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
cout<<res.p.p[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
*/
return true;
}
int main(){
int test;
int cnt1=0;
int cnt2=0;
cin>>w>>h>>k;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
char m;
cin>>m;
if(m=='R') c.car[cnt1++]={i,j};
if(m=='D') c.goal[cnt2++]={i,j};
c.p.p[i][j]=m;
}
}
st.insert(c.p);
q.push(c);
while(!q.empty()){
c=q.front();
q.pop();
for(int i=0;i<cnt2;i++){
int t1=c.goal[i].first;
int t2=c.goal[i].second;
if(c.p.p[t1][t2]=='R'){
ans=true;
test=c.cnt;
break;
}
}
if(ans) break;
if(c.cnt>=k) continue;
for(int i=0;i<cnt1;i++){
for(int j=1;j<=4;j++){
node res=c;
res.cnt++;
if(move(res,i,j)){
if(st.count(res.p)) continue;
else st.insert(res.p),q.push(res);
}
}
}
}
if(ans) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}