USACO 3.3

洛谷 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 亞瑟王的宮殿

題目

洛谷
USACO


分析

考慮答案也就是n1n-1個騎士到集合點,剩下一個騎士先到與國王的會合點再到集合點的距離,可以發現,國王到某個點的距離就是切比雪夫距離,
首先對於每個點都對外跑一遍bfs,然後枚舉集合點,再枚舉與國王會合的騎士,再枚舉他們的匯合點,時間複雜度O(R3C3)O(R^3C^3),實際遠低於這一時間複雜度,而且可以玄學地選擇國王周圍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,設dp[i][j]dp[i][j]表示以(i,j)(i,j)爲右下角的正方形的最大邊長,那麼dp[i][j]=min(dp[i1][j],dp[i][j1],dp[i1][j1])+1dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1


代碼

/*
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 遊戲

題目


分析

維護前綴和,可以知道,第二個人的最優方案也就是總和減去第一個人的最優方案
dp[i][j]dp[i][j]表示第一個人選區間[lr][l\sim r]的最優方案,那麼dp[i][j]=s[j]s[i1]min(dp[i+1][j],dp[i][j1])dp[i][j]=s[j]-s[i-1]-min(dp[i+1][j],dp[i][j-1])


代碼

/*
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]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章