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

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

一 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
",a[cnt-1].id);
    }
    else{
        dfs(cnt-1,y);
        printf("%d 6
",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
");
            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
");
        else{
            printf("%d
",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
",h,w,l);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++) printf("%c",list[i]);
        printf("
");
        for(int j=0;j<n;j++) printf("%c",list[j]);
        if (i!=n-1) printf("

");
        else printf("
");
    }
    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[n]>=0) return sg[n];
    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[n]=i;
}
int main()
{
    memset(sg,-1,sizeof(sg));
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(dfs(n)) puts("1");
        else puts("2");
    }
}


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

原文地址:https://www.cnblogs.com/cyendra/p/3681560.html