洛谷 2731 騎馬修柵欄
題目
給定一個無向圖,找到一條路徑,使它經過無向圖的所有邊,並且字典序最小
分析
這是一個一筆畫的問題,考慮找到奇點,從奇點開始深搜,沒、每經過一條邊刪掉一次
代碼
/*
ID:lemondi1
LANG:C++
TASK:fence
*/
#include <cstdio>
#include <cctype>
#include <stack>
#define rr register
using namespace std;
int mp[501][501],deg[501],root; stack<int>q;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void dfs(int x){
for (rr int i=1;i<=500;++i)
if (mp[x][i]){
--mp[x][i],--mp[i][x];
dfs(i);
}
q.push(x);
}
signed main(){
freopen("fence.in","r",stdin);
freopen("fence.out","w",stdout);
for (rr int m=iut();m;--m){
rr int x=iut(),y=iut();
++mp[x][y],++mp[y][x],
++deg[x],++deg[y];
}
for (rr int i=1;i<=500;++i)
if (deg[i]) {root=i; break;}
for (rr int i=1;i<=500;++i)
if (deg[i]&1) {root=i; break;}
dfs(root);
while (q.size()) print(q.top()),putchar(10),q.pop();
return 0;
}
洛谷 2732 商品購物
題目
有最多5種商品,每種商品都有花費和所需的數量,有些商品的組合能有更優惠的價格,問買完所需數量商品的最小花費
分析
完全揹包,不多說
代碼
/*
ID:lemondi1
LANG:C++
TASK:shopping
*/
#include <cstdio>
#include <cstring>
#include <cctype>
#define rr register
using namespace std;
int n,cnt,rk[1007],ned[107][6],fwe[107],dp[6][6][6][6][6],nwe[6],amo[6];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void Mn(int &a,int b){a=a<b?a:b;}
signed main(){
freopen("shopping.in","r",stdin);
freopen("shopping.out","w",stdout);
n=iut(),memset(rk,-1,sizeof(rk));
for (rr int i=0;i<n;++i){
rr int tot=iut();
for (rr int j=0;j<tot;++j){
rr int now1=iut(),now2=iut();
if (rk[now1]==-1) rk[now1]=cnt++;
ned[i][rk[now1]]=now2;
}
fwe[i]=iut();
}
for (rr int i=iut();i;--i){
rr int now1=iut(),now2=iut(),w=iut();
if (rk[now1]==-1) rk[now1]=cnt++;
nwe[rk[now1]]=w,amo[rk[now1]]=now2;
}
for (rr int i=0;i<=amo[0];++i)
for (rr int j=0;j<=amo[1];++j)
for (rr int k=0;k<=amo[2];++k)
for (rr int p=0;p<=amo[3];++p)
for (rr int h=0;h<=amo[4];++h){
rr int &t=dp[i][j][k][p][h]=i*nwe[0]+j*nwe[1]+k*nwe[2]+p*nwe[3]+h*nwe[4];
for (rr int now=0;now<n;++now)
if (i>=ned[now][0]&&j>=ned[now][1]&&k>=ned[now][2]&&p>=ned[now][3]&&h>=ned[now][4])
Mn(t,dp[i-ned[now][0]][j-ned[now][1]][k-ned[now][2]][p-ned[now][3]][h-ned[now][4]]+fwe[now]);
}
return !printf("%d\n",dp[amo[0]][amo[1]][amo[2]][amo[3]][amo[4]]);
}
洛谷 1930 亞瑟王的宮殿
題目
分析
考慮答案也就是個騎士到集合點,剩下一個騎士先到與國王的會合點再到集合點的距離,可以發現,國王到某個點的距離就是切比雪夫距離,
首先對於每個點都對外跑一遍bfs,然後枚舉集合點,再枚舉與國王會合的騎士,再枚舉他們的匯合點,時間複雜度,實際遠低於這一時間複雜度,而且可以玄學地選擇國王周圍5*5的位置作爲匯合點(雖然沒有正確性)
代碼
/*
ID:lemondi1
LANG:C++
TASK:camelot
*/
#include <iostream>
#include <queue>
#include <cstring>
#define rr register
using namespace std;
const int dx[8]={-1,-1,-2,-2,1,1,2,2},dy[8]={2,-2,1,-1,2,-2,1,-1};
struct rec{int x,y;}kn[1201]; queue<rec>q;
int v[41][31],dis[41][31][41][31],r,c;
inline signed max(int a,int b){return a>b?a:b;}
inline void bfs(int qx,int qy){
memset(v,0,sizeof(v));
q.push((rec){qx,qy}),v[qx][qy]=1,dis[qx][qy][qx][qy]=0;
while (q.size()){
rr int nx=q.front().x,ny=q.front().y; q.pop();
for (rr int k=0;k<8;++k){
rr int zx=nx+dx[k],zy=ny+dy[k];
if (zx<1||zx>r||zy<1||zy>c||v[zx][zy]) continue;
dis[qx][qy][zx][zy]=dis[qx][qy][nx][ny]+1;
q.push((rec){zx,zy}),v[zx][zy]=1;
}
}
}
inline signed aabs(int x){return x<0?-x:x;}
signed main(){
freopen("camelot.in","r",stdin);
freopen("camelot.out","w",stdout);
cin.tie(0),cout.tie(0),cin>>r>>c,
ios::sync_with_stdio(0); rr char roww;
memset(dis,42,sizeof(dis));
rr int colu,cnt=-1,ans=dis[0][0][0][0];
while (cin>>roww>>colu){
rr rec t=(rec){colu,roww^64};
kn[++cnt]=t;
}
for (rr int i=1;i<=r;++i)
for (rr int j=1;j<=c;++j) bfs(i,j);
for (rr int i=1;i<=r;++i)
for (rr int j=1;j<=c;++j){
rr int sum=0;
for (rr int k=1;k<=cnt;++k) sum+=dis[kn[k].x][kn[k].y][i][j];
ans=min(ans,sum+max(aabs(kn[0].x-i),aabs(kn[0].y-j)));
for (rr int k=1;k<=cnt;++k){
sum-=dis[kn[k].x][kn[k].y][i][j];
rr int lx=max(kn[0].x-2,1),ly=max(kn[0].y-2,1),rx=min(kn[0].x+2,r),ry=min(kn[0].y+2,c);
for (rr int ii=lx;ii<=rx;++ii)
for (rr int jj=ly;jj<=ry;++jj)
ans=min(ans,sum+dis[kn[k].x][kn[k].y][ii][jj]+max(aabs(ii-kn[0].x),aabs(jj-kn[0].y))+dis[ii][jj][i][j]);
sum+=dis[kn[k].x][kn[k].y][i][j];
}
}
cout<<ans<<endl;
return 0;
}
洛谷 2733 家的範圍
題目
問一個01矩陣中有多少個邊長超過1的正方形(超簡化)
分析
dp,設表示以爲右下角的正方形的最大邊長,那麼
代碼
/*
ID:lemondi1
LANG:C++
TASK:range
*/
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
int dp[251][251],n,m,ans[251];
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed mIn(int a,int b,int c){return min(min(a,b),c);}
signed main(){
freopen("range.in","r",stdin);
freopen("range.out","w",stdout);
scanf("%d",&n);
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=n;++j){
rr char c=getchar();
while (!isdigit(c)) c=getchar();
if (c^49) continue;
dp[i][j]=mIn(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1;
++ans[dp[i][j]];
}
for (rr int i=n;i>1;--i) ans[i-1]+=ans[i];
for (rr int i=2;i<=n;++i)
if (!ans[i]) break;
else print(i),putchar(32),print(ans[i]),putchar(10);
return 0;
}
洛谷 2734 遊戲
分析
維護前綴和,可以知道,第二個人的最優方案也就是總和減去第一個人的最優方案
設表示第一個人選區間的最優方案,那麼
代碼
/*
ID:lemondi1
LANG:C++
TASK:game1
*/
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
int n,s[101],dp[101][101];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
signed main(){
freopen("game1.in","r",stdin);
freopen("game1.out","w",stdout);
n=iut();
for (rr int i=1;i<=n;++i)
s[i]=s[i-1]+(dp[i][i]=iut());
for (rr int i=n-1;i>=1;--i)
for (rr int j=i+1;j<=n;++j)
dp[i][j]=s[j]-s[i-1]-min(dp[i+1][j],dp[i][j-1]);
return !printf("%d %d\n",dp[1][n],s[n]-dp[1][n]);
}