P2765 魔术球问题 (网络流)
阅读原文时间:2023年07月08日阅读:2

题意:n根柱子 把编号1,2,3….的球依次插到柱子上去

   需要满足相邻的两个球编号加起来为完全平方数 n < 55

题解:网络流24(23)题里的

   但是一直不知道怎么建图  或者说建图的意义

   一般都要套路拆点 我的理解就是实际问题背景每个点是需要双向边的 但是网络流算法要建反向边 所以就拆点防止重边 意义更明确

   这个题的话把小球拆点就表示 一个放前面 一个放后面的情况 然后按题意建图 跑最大流

   我最开始以为一条增广路代表一根柱子 其实不是 这里柱子的意义更抽象

   模拟一下程序后发现 在依次加球的过程中 最大流跑通表示的是这个球可以直接接在当前安排方式的后面

   如果跑不通 就要新开柱子了 同时跑新的最大流也能保证反悔操作

#include
using namespace std;

int n, cnt, p, num, s, t, maxflow;

struct node {
int to, nex, val;
}E[200005];
int head[4005];
int cur[4005];

void addedge(int x, int y, int va) {
E[++cnt].to = y; E[cnt].nex = head[x]; E[cnt].val = va; head[x] = cnt;
E[++cnt].to = x; E[cnt].nex = head[y]; E[cnt].val = 0; head[y] = cnt;
}

int dep[4005];
int to[4005];
int inque[4005];
bool bfs() {
for(int i = 0; i <= num * 2 + 2; i++) cur[i] = head[i], dep[i] = 0x3f3f3f3f, inque[i] = 0; dep[s] = 0; queue que;
que.push(s);
inque[s] = 1;

while(!que.empty()) {  
    int u = que.front();  
    que.pop();

    for(int i = head\[u\]; i; i = E\[i\].nex) {  
        int v = E\[i\].to;  
        if(E\[i\].val > 0 && dep\[v\] > dep\[u\] + 1) {  
            dep\[v\] = dep\[u\] + 1;  
            if(!inque\[v\]) {  
                inque\[v\] = 1;  
                que.push(v);  
            }  
        }  
    }  
}  
if(dep\[t\] != 0x3f3f3f3f) return true;  
return false;  

}

int vis;
int dfs(int x, int flow) {
if(x == t) {
vis = 1;
maxflow += flow;
return flow;
}

int rflow = 0;  
int used = 0;  
for(int i = cur\[x\]; i; i = E\[i\].nex) {  
    cur\[x\] = i;  
    int v = E\[i\].to;  
    if(E\[i\].val > 0 && dep\[v\] == dep\[x\] + 1) {  
        if(rflow = dfs(v, min(flow - used, E\[i\].val))) {  
            to\[x / 2\] = v / 2;  
            used += rflow;  
            E\[i\].val -= rflow;  
            E\[i ^ 1\].val += rflow;  
            if(used == flow) break;  
        }  
    }  
}  
return used;  

}

void dinic() {
maxflow = 0;
while(bfs()) {
vis = 1;
while(vis) {
vis = 0;
dfs(s, 100000000);
}
}
}

int ans[60];

int main() {
p = num = 0;
cnt = 1;
scanf("%d", &n);
s = 0; t = 1;
while(p <= n) {
num++;
addedge(s, num << 1, 1);
addedge(num << 1 | 1, t, 1);
for(int i = sqrt(num) + 1; i * i < 2 * num; i++) {
addedge((i * i - num) << 1, num << 1 | 1, 1);
}

    dinic();  
    if(!maxflow) {  
        ans\[++p\] = num;  
    }  
}  
printf("%d\\n", num - 1);

for(int i = 1; i <= n; i++) {  
    printf("%d", ans\[i\]);  
    for(int j = ans\[i\]; to\[j\]; j = to\[j\]) printf(" %d", to\[j\]);  
    puts("");  
}  
return 0;  

}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章