您的位置:首页 > 其它

叉姐的魔法训练(第八课)---- 幽默术

2013-10-06 13:32 211 查看
--------------

一 MSTDP

POJ 3538 Domestic Networks

有n个点m条边,和5型6型两种线,每米花费p5、p6,各有q5、q6米。

每条边要么用

5型连接要么用6型,或不连接。

求将n个点连接的最小花费。与最小花费的方案。

首先求出最小生成树。

在对树上的边进行dp。

f[ i ][ j ] 表示 前i条路用5型j米的最小花费。

f[i][j]=f[i-1][j]+c*p6 (第i条路不使用5型)

f[i][j]=f[i-1][j-c]+c*p5 (第i条路使用5型)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define rst(x) memset(x,0,sizeof(x))
#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
using namespace std;

const int maxn=1111;
const int maxm=11111;
const int INF=0x3f3f3f3f;
int n,m;

struct Edge{
int u;
int v;
int w;
int id;
bool operator<(const Edge& rhs) const{
return w<rhs.w;
}
}road[maxm];
struct Node{
int w;
int id;
Node(int w,int id){
this->w=w;
this->id=id;
}
bool operator<(const Node& rhs) const{
return id<rhs.id;
}
};

int pa[maxn];
void makeSet(int n){
for (int i=0;i<=n;i++) pa[i]=i;
}
int findSet(int x){
if (x!=pa[x]) pa[x]=findSet(pa[x]);
return pa[x];
}
void unionSet(int x,int y){
x=findSet(x);
y=findSet(y);
if (x!=y) pa[x]=y;
}

int p5,q5,p6,q6;
int sum,num;
vector<Node>a;

int f[1005][10005];
int path[1005][10005];

void dfs(int cnt,int y){
if (!cnt) return;
if (path[cnt][y]!=y){
dfs(cnt-1,path[cnt][y]);
printf("%d 5\n",a[cnt-1].id);
}
else{
dfs(cnt-1,y);
printf("%d 6\n",a[cnt-1].id);
}
}

int main()
{
while (~scanf("%d%d",&n,&m)){
makeSet(n);
a.clear();
for (int i=0;i<m;i++){
scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].w);
road[i].id=i+1;
}
scanf("%d%d%d%d",&p5,&q5,&p6,&q6);
sort(road,road+m);
sum=0;
for (int i=0;i<m;i++){
int u=road[i].u;
int v=road[i].v;
int w=road[i].w;
if (findSet(u)!=findSet(v)){
unionSet(u,v);
a.push_back(Node(road[i].w,road[i].id));
sum+=w;
}
}
if (sz(a)!=n-1||sum>q5+q6){
printf("Impossible\n");
continue;
}
sort(a.begin(),a.end());
memset(f,0x3f,sizeof(f));
int total=0;
f[0][0]=0;
for (int i=1;i<=sz(a);i++){
total+=a[i-1].w;
int c=a[i-1].w;
for (int j=q5;j>=0;j--){
if (total-j<=q6&&f[i-1][j]!=INF&&f[i-1][j]+c*p6<f[i][j]){
f[i][j]=f[i-1][j]+c*p6;
path[i][j]=j;
}
if (j>=c&&f[i-1][j-c]!=INF&&f[i-1][j-c]+c*p5<f[i][j]){
f[i][j]=f[i-1][j-c]+c*p5;
path[i][j]=j-c;
}
}
}
int ans=INF,y=-1;
for (int i=0;i<=q5;i++){
if (ans>f[sz(a)][i]){
ans=f[sz(a)][i];
y=i;
}
}
if (ans==INF) printf("Impossible\n");
else{
printf("%d\n",ans);
dfs(sz(a),y);
}
}
return 0;
}


-------------------------------

二 构造方案

POJ 3566 Building for UN

题解摘自网络:

题目大意:要建新的联合国总部,每个国家都有若干相连的房间,请你设计一种方案,使每个国家的都有房子能够与其他国家的某个房间相邻,使这两个国家可以讨论秘密国事。用字母表示这些国家。

下面这样的方案就能满足题目的要求,而且能够满足各种n。例如,n=4:

ABCD

AAAA

ABCD

BBBB

ABCD

CCCC

ABCD

DDDD

相当于每个国家在每层楼各有一个办公室,从纵向看,一个竖条都是一个国家。每个国家在某层都有一个阳台,通向其他国家的办公室。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn=1111;
int a[2][maxn];
char list[maxn];
int main()
{
int n,h,w,l;
for(int i=0;i<26;i++) list[i]='A'+i;
for(int i=0;i<26;i++) list[26+i]='a'+i;
scanf("%d",&n);
h=n,w=n,l=2;
printf("%d %d %d\n",h,w,l);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++) printf("%c",list[i]);
printf("\n");
for(int j=0;j<n;j++) printf("%c",list[j]);
if (i!=n-1) printf("\n\n");
else printf("\n");
}
return 0;
}


-------------------------------

三 SG分解

POJ 3537 Crosses and Crosses

摘自学姐博客:在第I个位置放一个X,即可分为两个子游戏,I-3和n-I-2

#include<iostream>
#include<cstdlib>
#include<stdio.h>
#include<memory.h>
using namespace std;
int sg[2100];
int dfs(int n)
{
if(n<0) return 0;//n<0
if(sg
>=0) return sg
;
bool g[2001]={0};
for(int i=1;i<=n;i++)
{
int t=dfs(i-3)^dfs(n-i-2);
g[t]=1;
}
for(int i=0;;i++)
if(g[i]==0) return sg
=i;
}
int main()
{
memset(sg,-1,sizeof(sg));
int n;
while(scanf("%d",&n)!=EOF)
{
if(dfs(n)) puts("1");
else puts("2");
}
}


-------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: