Steiner tree study notes

This information may not know where to learn road, very little information online. Or find a few dozen chiefs blog to go with it:

https://www.cnblogs.com/ECJTUACM-873284962/p/7643445.html#autoid-0-0-0

https://www.cnblogs.com/zwfymqz/p/8977295.html

 

Konjac bloggers did not understand the deep, and now it seems to me Steiner tree is actually a kind of problem: given an undirected graph, select some edges make a few specific points that connect the Steiner tree and the right side is the smallest and The minimum Steiner tree . It would appear the minimum spanning tree is actually a special Steiner tree, requires a minimum spanning tree connecting all the dots. Then the minimum Steiner tree how demand? The upper two solutions are given like bloggers pressure dp + shortest relaxation.

On top of Angel_Kitty chiefs said more clearly:

Overall between different state is a state with pressure dp like to solve, the state between the state with the same SPFA to relax. Each layer is connected to a bit state of feeling, with different layers like pressure dp solved, and then only in the same layer came SPFA relaxation time is relatively stable so excellent. (Of course AngelKitty Bowen was also mentioned other solutions, such as direct or layered shortest road race first and then let Floyd pretreatment pure dp run, the former of these two approaches is slow which can only apply to a very small n Case).

Then tell the truth I can only think this algorithm is correct in the sense that, but very specific reason could not say, mainly about the solution is not very deep understanding qwq.

 

ok then do is follow Gangster problem areas:

Luo Gu P4294 tour plans

Steiner tree is basically a bare title, write a template when you can use. Solving substantially frame-like pressure on the Steiner trees dp + SPFA Thus, the specific state transition equation is then spfa specific topics and specific analysis.

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=1050;
const int INF=0x3f3f3f3f;
const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
int n,m,num,a[12][12],dp[12][12][N];
struct PRE{ int x,y,s; } pre[12][12][N];

queue<pii> q;
bool inq[12][12]; 
void spfa(int now) {  //同层dpfa松弛 
    while (!q.empty()) {
        pii u=q.front(); q.pop();
        for (int i=0;i<4;i++) {
            int x=u.first+dx[i],y=u.second+dy[i];
            if (x<1 || x>n || y<1 || y>m) continue;
            if (dp[x][y][now]>dp[u.first][u.second][now]+a[x][y]) {
                dp[x][y][now]=dp[u.first][u.second][now]+a[x][y];
                pre[x][y][now]=(PRE){u.first,u.second,now};
                if (!inq[x][y]) q.push(make_pair(x,y)),inq[x][y]=1;
            }
        }
        inq[u.first][u.second]=0;
    }
}

void dfs(int x,int y,int now) {
    inq[x][y]=1;
    if (!x || !y) return;
    PRE tmp=pre[x][y][now];
    dfs(tmp.x,tmp.y,tmp.s);
    if (x==tmp.x && y==tmp.y) dfs(x,y,now-tmp.s);  //(x,y,now)是由子集转移过来的 
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(dp,0x3f,sizeof(dp));
    num=0;  //点集的点个数 
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) {
            scanf("%d",&a[i][j]);
            if (!a[i][j]) dp[i][j][1<<num]=0,num++;
        }
    int ALL=(1<<num)-1;
    for (int sta=0;sta<=ALL;sta++) {  //遍历每一层 
        for (int i=1;i<=n;i++)
            for (int j=1; J <= m; J ++ ) {
                 for ( int S = STA; S; S = (S- . 1 ) & STA) {   // Enumeration subset 
                    IF (DP [I] [J] [STA]> DP [I ] [J] [S] + DP [I] [J] [STA-S] - A [I] [J]) { 
                        DP [I] [J] [STA] = DP [I] [J] [S ] + DP [I] [J] [STA-S] - A [I] [J]; 
                        pre [I] [J] [STA] = (the pRE) {I, J, S};   // record predecessor state program for outputting 
                    } 
                } 
                IF (DP [I] [J] [STA] <INF) q.push (the make_pair (I, J)), INQ [I] [J] = . 1 ;   // slack others 
            } 
        SPFA ( STA); 
    }     
    
    int RX, ry, Min =INF;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            if (!a[i][j] && dp[i][j][ALL]<Min) Min=dp[i][j][ALL],rx=i,ry=j;
    printf("%d\n",dp[rx][ry][ALL]);
    memset(inq,0,sizeof(inq));
    dfs(rx,ry,ALL);  //dfs沿着前驱状态走输出方案
    for (int i=1;i<=n;i++,puts(""))
        for (int j=1;j<=m;j++)
            if (a[i][j]==0) printf("x");
            else if (inq[i][j]) printf("o");
            else printf("_");    
    return 0;
} 
View Code

 

HDU-4085 Peach Blossom Spring

Steiner tree Classic title. But note that this problem only requires point to communicate with each other, does not require that all points of communication! Our solution is: first of all the key points, or make a minimum Steiner tree to get an answer at all connected, and then we find a way to become the basis of these tree forest. We Rethinking forest is actually what? Multi-tree forest is actually split or a combination of a few trees disconnected from, then we follow the definition of forest from a combination of answers to a few trees into the forest!

Provided ANS [sta] sta connected state of minimum weight value forest ANS [sta], initial ANS [sta] is equal to all dp [i] Min [sta] in, why? Because at this time we replaced the forest angle to think about, we only care about the connection status does not care about the root of the forest (forest and of course no root, just such a principle). After initialization we begin the transfer, the transfer equation is readily available comparison ans [sta] = min (ans [s] + ans [sta-s]) we have the angle from the forest (s sta is a subset of), where the transfer thinking, we only care about the connection status, so the two are not even connected to the forest did not matter, the same goal can be combined into a connected state sta. So we have small to large enumeration sta, then enumerate the subset of sta transferred. The resulting forest is the smallest.

This is still a small detail: because of the special requirements of the subject person must (1-k dot) and the house (k + 1-2k points) was only seen as the same number of legal status and can be transferred.

#include<bits/stdc++.h>
using namespace std;
const int N=1050;
const int INF=0x3f3f3f3f;
int n,m,k,ALL,dp[55][N],ans[N];

int cnt,head[55],nxt[2010],to[2010],len[2010];
void add_edge(int x,int y,int z) {
    nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
}

queue<int> q;
bool inq[55];
void spfa(int now) {
    while (!q.empty()) {
        int x=q.front(); q.pop();
        for (int i=head[x];i;i=nxt[i]) {
            int y=to[i];
            if (dp[y][now]>dp[x][now]+len[i]) {
                dp[y][now]=dp[x][now]+len[i];
                if (!inq[y]) q.push(y),inq[y]=1;
            }
        }
        inq[x]=0;
    }
}

bool check(int sta) {
    int ret=0;
    for (int i=1;i<=2*k;i++) 
        if (sta&(1<<(i-1)))
            if (i<=k) ret++; else ret--;
    return ret==0;        
}

int main()
{
    int T; cin>>T;
    while (T--) {
        scanf("%d%d%d",&n,&m,&k);
        cnt=1; memset(head,0,sizeof(head));
        for (int i=1;i<=m;i++) {
            int x,y,z; scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z); add_edge(y,x,z);
        }
        ALL=(1<<(2*k))-1; memset(inq,0,sizeof(inq));
        for (int i=1;i<=n;i++) for (int j=0;j<=ALL;j++) dp[i][j]=INF;
        for (int i=1;i<=k;i++) dp[i][1<<(i-1)]=0;
        for (int i=n-k+1;i<=n;i++) dp[i][1<<(i-n+2*k-1)]=0;
        
        for (int sta=0;sta<=ALL;sta++) {
            for (int i=1;i<=n;i++) {
                for (int s=sta;s;s=(s-1)&sta)
                    dp[i][sta]=min(dp[i][sta],dp[i][s]+dp[i][sta-s]);
                if (dp[i][sta]<INF) q.push(i),inq[i]=1;    
            }
            spfa(sta);
        }
        
        for (int sta=0;sta<=ALL;sta++) {
            ans[sta]=INF;
            for (int i=1;i<=n;i++)
                ans[sta]=min(ans[sta],dp[i][sta]);
        }
        for (int sta=0;sta<=ALL;sta++) if (check(sta))
            for (int s=sta;s;s=(s-1)&sta) if (check(s))
                ans[sta]=min(ans[sta],ans[s]+ans[sta-s]);
                
        if (ans[ALL]>=INF) puts("No solution"); else printf("%d\n",ans[ALL]);
    }    
    return 0;
} 
View Code

 

As such-3613 wormhole Transport

This question is almost like HDU4085. Because the connection factory and resource point on it, that is the smallest forest, practices like HDU4085 as, first of all point to do the minimum required minimum Steiner tree, then dp forest, while up to the point answer to the minimum weight recorded.

Here and HDU4085 difference is that a reasonable state of this problem requires that the number of factories> = the number of resource points , which is why? Because we finish the synthetic minimal Steiner trees with the forest when dp ans [sta] = min (ans [s] + ans [sta-s]) Here it must be noted s tree forest tree and sta-s forests must be separated , can not appear point s resources and sta-s factories connection this case! So we only factory> = Resource status was seen as a legitimate point, then we can guarantee each resource point only in their own forest Fengyun connection is not got to go to other forest.

Overall requirements for legal status in order to prevent two forest actually influence each other to merge get the wrong answer.

So why not make resource points> = factory it? It seems in theory, can also block the interaction merge two forests, but because of the special nature of this problem, the number of plants of each planet can be more than one, but less than or equal to 1 resource point only, so if resource points> = factories legal status if, once the number of occurrence of each planet plant> when the number of resource points, then each state is considered illegal, it can not shifted. But in turn, this will not happen. So factory> = resource this is a very clever way, it is able to avoid the impact of the forest, the answer will not miss the program. In fact, we can think only factory == resources program points we want, but we can not be like the previous question, like the factory == resources point is defined as legitimate, because there is not a weight for each point is 1, this definition will be unable to transfer the case, we can only make resource points> = factory, but such a definition would include cases factory == resource points, it is possible. (Here you might think that a question on the change ==> = is not it also possible, bloggers have tested indeed, because it is also preventing the forest influence)

Thought here konjac bloggers have doubts: it would mean that if a planet and plant resources can be greater than 1 would mean that no solution? I think only in accordance with the above seems to be no good way.

#include<bits/stdc++.h>
using namespace std;
const int N=1050;
const int M=5e3+10;
const int INF=0x3f3f3f3f;
int n,m,num,ALL,id[210],w[210],p[210],dp[210][N],ans[N];

int cnt,head[210],nxt[M<<1],to[M<<1],len[M<<1];
void add_edge(int x,int y,int z) {
    nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
}

queue<int> q;
bool inq[210];
void spfa(int now) {
    while (!q.empty()) {
        int x=q.front(); q.pop();
        for (int i=head[x];i;i=nxt[i]) {
            int y=to[i];
            if (dp[y][now]>dp[x][now]+len[i]) {
                dp[y][now]=dp[x][now]+len[i];
                if (!inq[y]) q.push(y),inq[y]=1;
            }
        }
        inq[x]=0;
    }
}

int getp(int sta) {
    int ret=0;
    for (int i=1;i<=num;i++) 
        if (sta&(1<<(i-1))) ret+=p[id[i]];
    return ret;        
}

int getw(int sta) {
    int ret=0;
    for (int i=1;i<=num;i++)
        if (sta&(1<<(i-1))) ret+=w[id[i]];
    return ret;    
}

int main()
{
    while (scanf("%d",&n)==1) {
        num=0;
        for (int i=1;i<=n;i++) {
            scanf("%d%d",&p[i],&w[i]);
            if (p[i] || w[i]) id[++num]=i;
        }
        scanf("%d",&m);
        cnt=1; memset(head,0,sizeof(head));
        for (int i=1;i<=m;i++) {
            int x,y,z; scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z); add_edge(y,x,z);
        }
        ALL=(1<<num)-1; memset(inq,0,sizeof(inq));
        for (int i=1;i<=n;i++) for (int j=0;j<=ALL;j++) dp[i][j]=INF;
        for (int i=1;i<=num;i++) dp[id[i]][1<<(i-1)]=0;
        
        for (int sta=0;sta<=ALL;sta++) {
            for (int i=1;i<=n;i++) {
                for (int s=sta;s;s=(s-1)&sta)
                    dp[i][sta]=min(dp[i][sta],dp[i][s]+dp[i][sta-s]);
                if (dp[i][sta]<INF) q.push(i),inq[i]=1;    
            }
            spfa(sta);
        }
        
        for (int sta=0;sta<=ALL;sta++) {
            ans[sta]=INF;
            for (int i=1;i<=n;i++)
                ans[sta]=min(ans[sta],dp[i][sta]);
        }
        int Max=0,Min=INF;
        for (int sta=0;sta<=ALL;sta++) 
            if (getp(sta)>=getw(sta)) {
                for (int s=sta;s;s=(s-1)&sta) 
                    if (getp(s)>=getw(s) && getp(sta-s)>=getw(sta-s))
                    ans[sta]=min(ans[sta],ans[s]+ans[sta-s]);
                if (getw(sta)>Max || getw(sta)==Max && ans[sta]<Min) Max=getw(sta),Min=ans[sta];
            }
        printf("%d %d\n",Max,Min);            
    }
    return 0;
}
View Code

 

Guess you like

Origin www.cnblogs.com/clno1/p/10990936.html