• ACM算法集锦


    kurXX最小生成树

    #include <iostream>

    #include <math.h>

    #include <algorithm>

    using namespace std;

    #define M 501

    #define LIM 20000000

    struct edg{

             int u,v;

             int w;

    }all_e[M*M/2];

    bool operator < (const edg &a,const edg &b){

             return a.w<b.w;

    }

    int set[M];

    inline bool uni(int set[],int a,int b){

             int ac=0,a2=a,b2=b,bc=0;

             while(set[a]!=0) {a=set[a];ac++;}

             if(a2!=a) set[a2]=a;

             while(set[b]!=0) {b=set[b];bc++;}

             if(b2!=b) set[b2]=b; 

             if(a==b) return false;

             if(ac<bc) set[a]=b;

             else set[b]=a;

             return true;

    }

    int main(){

             int i,j,k,n,m,u,v,t;

             cin >> t;

             for(k=0;k<t;k++){

             memset(set,0,sizeof(set));

             cin >> n;

             int ei=0;

             for(i=1;i<=n;i++){

                       for(j=1;j<=n;j++){

                                if(t!=0){

                                         edg e;

                                         e.u=i;e.v=j;

                                         scanf("%d",&e.w);

                                         if(i<j)

                                                   all_e[ei++]=e;

                                }

                       }

             }

             sort(&all_e[0],&all_e[ei]);

             int count=0;

             int size=ei;

             int max=0;

             for(i=0;i<size && count < n-1;i++){

                       if(uni(set,all_e[i].u,all_e[i].v)){

                                count++;

                                if(all_e[i].w>all_e[max].w) max=i;

                       }

             }

             printf("%d ",all_e[max].w);

             }

             return 0;

    }

    Prim

    #include <iostream>

    using namespace std;

    #define M 2001

    int set[M]={0},g[M][M];

    char str[M][8];

    inline void make_map(int n,int g[M][M]){

             int i,j,k;

             for(i=1;i<=n;i++){

                       for(j=i+1;j<=n;j++){

                                int c=0;

                                for(k=0;k<7;k++)

                                         if(str[i][k]!=str[j][k]) c++;

                                g[i][j]=g[j][i]=c;

                       }

             }

    }

    int main(){

             int n,q[M],qf=0,ql=0,d[M],u;

             char c;

             scanf("%d%c",&n,&c);

             int i;

             while(n!=0){

                       memset(set,0,sizeof(set)); memset(g,0,sizeof(g));

                       for(i=1;i<=n;i++) {

                                scanf("%s",&str[i]);

                                q[i-1]=i;

                                d[i]=2000000;

                       }

                       qf=0;ql=n-1;

                       make_map(n,g);

                       int sum=0;

                       int f=false;

                       while(qf<=ql){

                                int min=qf;

                                for(i=qf+1;i<=ql;i++){

                                         if(d[q[i]] < d[q[min]]) min=i;

                                }

                                swap(q[qf],q[min]);

                                u=q[qf]; qf++;

                                if(f) sum+=d[u];

                                for(i=1;i<=n;i++){

                                         if(g[u][i] !=0 && g[u][i] < d[i]) d[i]=g[u][i];

                                }

                                f=true;

                       }

                       printf("The highest possible quality is 1/%d. ",sum);

                       scanf("%d%c",&n,&c);

             }

             return 0;

    }

    堆实现最短路

    #include <iostream>

    #include <string>

    #include <stdlib.h>

    #include <vector>;

    using namespace std;

    #define M 1001

    #define LIM 2000000000

    struct dd{ //最短距离

             int w,q;//w是距离值,q是堆中的相对位置

    }d[M],d2[M];

    struct node{

             int v,w;

    };

    int h[M],hs;

    vector<node> g[M],g2[M];

    void change_key(dd d[M],int v,int w){

             d[v].w=w;

             int i=d[v].q;

             while(i>1 && d[h[i/2]].w>d[h[i]].w){

                       swap(h[i],h[i/2]);

                       swap(d[h[i]].q,d[h[i/2]].q);

                       i=i/2;

             }

    }

    inline void min_heaphy(dd d[M],int *a,int i,int s){//s 为堆大小

             int l=i*2,r=i*2+1;

             int miner=i;

             if (l<=s && d[a[i]].w>d[a[l]].w)

                       miner = l;

             else miner=i;

             if (r<=s && d[a[miner]].w>d[a[r]].w)

                       miner=r;

             if(miner!=i){

                       swap(a[i],a[miner]);

                       swap(d[a[i]].q,d[a[miner]].q);

                       min_heaphy(d,a,miner,s);

             }

    }

    inline void init(dd d[M],int n,int s){  //初始化图和堆

             int i;

             hs=n;

             for(i=1;i<=n;i++){d[i].w=LIM;h[i]=d[i].q=i;}

             change_key(d,s,0);

    }

    inline void relax(dd d[M],int u,int v,int duv){

             if(d[v].w>d[u].w+duv) change_key(d,v,d[u].w+duv);

    }

    void dijkstra(vector<node> g[M],dd d[M],int n,int s){ //n is |V| && s is the source

             init(d,n,s);

             int i;

             while(hs!=0){

                       int u=h[1];

                       swap(h[1],h[hs]);

                       swap(d[h[1]].q,d[h[hs]].q);

                       hs--;

                       min_heaphy(d,h,1,hs);

                       for(i=0;i<g[u].size();i++) relax(d,u,g[u][i].v,g[u][i].w);

             }

    }

    最短路DIJ普通版

    #define M 101

    #define LIM 20000000

    int g[M][M],d[M],fd[2][M][M],gt[M][M],set[M];

    inline void init(int d[M],int n,int s){  //初始化图

             int i;

             for(i=1;i<=n;i++)         d[i]=LIM;

             d[s]=0;

    }

    inline void relax(int d[M],int u,int v,int duv){

             if(d[v]>d[u]+duv)        d[v]=d[u]+duv;

    }

    void dijkstra(int g[M][M],int d[M],int n,int s){ //n is |V| && s is the source

             init(d,n,s);

             int q[M],ql=1,qf=1; //队列

             int i;

             for(i=1;i<=n;i++) q[ql++]=i;

             while(qf!=ql){

                       int min=qf;

                       for(i=qf;i<ql;i++) if(d[q[i]]<d[q[min]]) min=i;

                       swap(q[qf],q[min]); //q[qf] is the min

                       int u=q[qf++];

                       for(i=1;i<=n;i++){

                                if(g[u][i]!=0) relax(d,u,i,g[u][i]);

                       }

             }

    }

    floyd

    #include <iostream>

    #include <vector>

    using namespace std;

    #define M 301

    #define LIM 200000000

    int w[M][M],d[2][M][M];

    void floyd(int g[M][M],int d[2][M][M],int n){

             int i,j,k;

             for(i=1;i<=n;i++){

                       for(j=1;j<=n;j++){

                                d[0][i][j]=g[i][j];

                       }

                       d[0][i][i]=0;

             }        //这里是令d[0]=g

             for(k=1;k<=n;k++){

                       for(i=1;i<=n;i++)

                                for(j=1;j<=n;j++){

                                         int t1=k%2; int t2=(t1+1)%2;

                                         d[t1][i][j]=d[t2][i][j] < d[t2][i][k]+d[t2][k][j]?d[t2][i][j]:d[t2][i][k]+d[t2][k][j];

                                }

             }

    }

    BELL_MAN

    inline void init(int d[M],int n,int s){  //初始化图

             int i;

             for(i=1;i<=n;i++)         d[i]=2000000000;

             d[s]=0;

    }

    inline void relax(int d[M],int u,int v,int duv){

             if(d[v]>d[u]+duv)        d[v]=d[u]+duv;

    }

    void bell_man(int g[M][M],int d[M],int n,int s){ //n个结点 s为源点

             int i,j,k;

             init(d,n,s);

             for(k=1;k<n;k++){

                       for(i=1;i<=n;i++)

                                for(j=1;j<=n;j++){

                                         if(g[i][j]!=0) relax(d,i,j,g[i][j]);

                                }

             }

    }

    拓扑排序

    #include <iostream>

    #include <stack>

    #include <vector>

    #include <list>

    using namespace std;

    vector <int> order;

    void find_id(list<int> g[],int id[],int n){  //寻找入度,没有使用

             int i;

             list<int>::iterator k;

             for(i=0;i<n;i++){

                       for(k=g[i].begin();k!=g[i].end();k++){

                                id[*k]++;

                       }

             }

    }

    void topo(list<int> g[],int id[],int n,bool &OK,bool &incon){//OK==false 表示未确定顺序 incon==true 表示发现矛盾

             stack<int> s;

             order.erase(order.begin(),order.end());

             int t[26];

             copy(&id[0],&id[n],&t[0]);

             int i;

             for(i=0;i<n;i++){

                       if(id[i]==0)

                                s.push(i);

             }

             if(s.size()!=1) OK=false;

             int count=0;

             while(!s.empty()){

                       int v=s.top(); s.pop(); count++;

                       order.push_back(v);

                       list<int>::iterator k;

                       for(k=g[v].begin();k!=g[v].end();k++){

                                id[*k]--;

                                if(id[*k]==0) s.push(*k);

                                if(s.size()>1) OK=false;

                       }

             }

             if(order.size() < n) OK=false;   //矛盾发生,会导致这种情况,小心

             if(count < n) incon=true;

             copy(&t[0],&t[n],&id[0]);

    }

    DFS强连通分支

    #include <iostream>

    #include <algorithm>

    #include <vector>

    using namespace std;

    #define M 20005

    vector<int> g[M],gt[M];

    bool used[M];

    int ft[M],sort_v[M],tim;

    bool comp(const int &u,const int &v){

             return ft[u]>ft[v];

    }

    inline int findp(int set[],int n){

             int n2=n;

             while(set[n]!=0) n=set[n];

             if(n2!=n) set[n2]=n;

             return n;

    }

    inline bool uni(int set[],int a,int b){

             int ac=0,a2=a,b2=b,bc=0,t;

             while(set[a]!=0) {a=set[a];ac++;}

             while(a2!=a) {t=set[a2]; set[a2]=a; a2=t;};

             while(set[b]!=0) {b=set[b];bc++;}

             while(b2!=b) {t=set[b2]; set[b2]=b; b2=t;};

             if(a==b) return false;

             if(ac<bc) set[a]=b;

             else set[b]=a;

             return true;

    }

    void dfs(vector<int> g[M],int u){

             if(used[u]) return;

             tim++;

             used[u]=true;

             int i;

             for(i=0;i<g[u].size();i++){

                       dfs(g,g[u][i]);

             }

             tim++;

             ft[u]=tim;

             return;

    }

    void dfs2(vector<int> g[],int u,int r,int set[]){

             if(used[u]) return;

             uni(set,u,r);

             used[u]=true;

             int i;

             for(i=0;i<g[u].size();i++){

                       dfs2(g,g[u][i],u,set);

             }

             return;

    }

    void scc(int n,vector<int> g[M],int set[]){

             int i,j;

             tim=0;

             memset(used,0,sizeof(used));

             memset(set,0,sizeof(set));

             for(i=1;i<=n;i++) sort_v[i]=i;

             for(i=1;i<=n;i++) if(!used[i]) dfs(g,i); //compute finishing times

             sort(&sort_v[1],&sort_v[n+1],comp); //decreasing f[u] order

             memset(used,0,sizeof(used)); 

             for(i=1;i<=n;i++) for(j=0;j<g[i].size();j++) gt[g[i][j]].push_back(i); //compute gt

             for(i=1;i<=n;i++) if(!used[sort_v[i]]) dfs2(gt,sort_v[i],sort_v[i],set);  //make the scc

    }

    int main(){

             int i,j,n,m,u,v,set[M];

             cin >> n >> m;

             for(i=0;i<m;i++){

                       scanf("%d%d",&u,&v);

                       g[u].push_back(v);

             }

             scc(n,g,set);

             int pi=1,ptosc[M];

             struct Scc{

                       int p,n;

             }sc[M];

             memset(sc,0,sizeof(sc));

             for(i=1;i<=n;i++){

                       int p=findp(set,i);

                       if(sc[p].p==0) {sc[p].p=pi; ptosc[pi++]=p;}

                       sc[p].n++;

             }

             int n2=pi-1,od[M];

             memset(od,0,sizeof(od));

             for(i=1;i<=n;i++){

                       for(j=0;j<g[i].size();j++){

                                u=findp(set,i); v=findp(set,g[i][j]);

                                if(sc[u].p!=sc[v].p) od[sc[u].p]++;

                       }

             }

             int sum=0,s1=0;

             for(i=1;i<=n2;i++) if(od[i]==0) {s1++; sum+=sc[ptosc[i]].n;}

             if(s1!=1) sum=0;

             cout << sum << endl;

    }

    最大匹配

    #include <iostream>

    #include <string>

    #include <math.h>

    using namespace std;

    #define M 1001

    int n,m,match[M],ans[M];

    bool visit[M],g[M][M];

    //O(n^3)

    bool dfs(int k,bool map[M][M]){ 

             int t;

             for(int i = 1; i <= m; i++){

                       if(map[k][i] && !visit[i]){

                                visit[i] = true;

                                t = match[i];

                                match[i] = k;

                                if(t == 0 || dfs(t,map))

                                         return true;

                                match[i] = t;

                       }

             }

             return false;

    }

    int main(){

             int i,sum=0,t,j,u,v;

             cin >> t;

             while(t--){

                       sum=0;

                       memset(match,0,sizeof(match));

                       memset(g,0,sizeof(g));

                       scanf("%d%d",&n,&m);

                       for(i=1;i<=m;i++){

                                scanf("%d%d",&u,&v);

                                g[u][v]=true;

                       }

                       m=n;

                       for(i=1;i<=n; i++){

                                memset(visit,0,sizeof(visit));

                                if(dfs(i,g))  sum++;

                       }

                       cout << n-sum << endl;

             }

             return 0;

    }

    还有两个最大匹配模板

    #include <iostream>

    #include <string>

    #include <math.h>

    #include <vector>

    using namespace std;

    #define M 3001

    bool g[M][M];

    int mk[M] ,cx[M],pred[M],open[M],cy[M],nx,ny;

    //边少适用O(n^3)

    int MaxMatchBFS()

    {

        int i , u , v , t , d , e , cur , tail , res(0) ;

        memset(mk , 0xff , sizeof(mk)) ;

        memset(cx , 0xff , sizeof(cx)) ;

        memset(cy , 0xff , sizeof(cy)) ;

        for (i = 0 ; i < nx ; i++){

            pred[i] = -1 ;

                       for (open[cur = tail = 0] = i ; cur <= tail && cx[i] == -1 ; cur++){

                for (u = open[cur] , v = 0 ; v < ny && cx[i] == -1 ; v ++) if (g[u][v] && mk[v] != i)

                {

                    mk[v] = i ; open[++tail] = cy[v] ; if (open[tail] >= 0) { pred[open[tail]] = u ; continue ; }

                    for (d = u , e = v ; d != -1 ; t = cx[d] , cx[d] = e , cy[e] = d , e = t , d = pred[d]) ;

                }

            }

            if (cx[i] != -1) res++ ;

        }

        return res ;

    }

    int path(int u){

        for (int v = 0 ; v < ny ; v++)

                       if (g[u][v] && !mk[v]){

                                mk[v] = 1 ;

                                if (cy[v] == -1 || path(cy[v])) {

                                         cx[u] = v ;

                                         cy[v] = u ;

                                         return 1 ;

                                }

                       } return 0 ;

    }

    //少适用O(n^3)

    int MaxMatchDFS()

    {

        int res(0) ;

        memset(cx , 0xff , sizeof(cx)) ;

        memset(cy , 0xff , sizeof(cy)) ;

        for (int i = 0 ; i < nx ; i++)

                       if (cx[i] == -1){

                                memset(mk , 0 , sizeof(mk));

                res += path(i) ;

                       }

                       return res ;

    }

    最大权匹配,KM算法

    //此KM算法,坐标从1开始,记住

    #include <iostream>

    #include <vector>

    #include <math.h>

    using namespace std;

    #define M 110

    int n;                // X 的大小

    int lx[M], ly[M];        // 标号

    bool sx[M], sy[M];    // 是否被搜索过

    int match[M];        // Y(i) 与 X(match [i]) 匹配

    // 从 X(u) 寻找增广道路,找到则返回 true

    bool path(int u,int weight[M][M]) {

        sx [u] = true;

        for (int v = 0; v < n; v ++)

            if (!sy [v] && lx[u] + ly [v] == weight [u] [v]) {

                sy [v] = true;

                if (match [v] == -1 || path(match [v],weight)) {

                    match [v] = u;

                    return true;

                }

            }

        return false;

    }

    // 参数 Msum 为 true ,返回最大权匹配,否则最小权匹配

    int km(bool Msum,int weight[M][M]) {

        int i, j;

        if (!Msum) {

            for (i = 0; i < n; i ++)

                for (j = 0; j < n; j ++)

                    weight [i] [j] = -weight [i] [j];

        }

        // 初始化标号

        for (i = 0; i < n; i ++) {

            lx [i] = -0x1FFFFFFF;

            ly [i] = 0;

            for (j = 0; j < n; j ++)

                if (lx [i] < weight [i] [j])

                    lx [i] = weight [i] [j];

        } 

        memset(match, -1, sizeof (match));

        for (int u = 0; u < n; u ++)

            while (1) {

                memset(sx, 0, sizeof (sx));

                memset(sy, 0, sizeof (sy));

                if (path(u,weight))

                    break;     

                // 修改标号

                int dx = 0x7FFFFFFF;

                for (i = 0; i < n; i ++)

                    if (sx [i])

                        for (j = 0; j < n; j ++)

                            if(!sy [j])

                                dx = min(lx[i] + ly [j] - weight [i] [j], dx);

                for (i = 0; i < n; i ++) {

                    if (sx [i])

                        lx [i] -= dx;

                    if (sy [i])

                        ly [i] += dx;

                }

            }

       

        int sum = 0;

        for (i = 0; i < n; i ++)

            sum += weight [match [i]] [i];

       

        if (!Msum) {

            sum = -sum;

            for (i = 0; i < n; i ++)

                for (j = 0; j < n; j ++)

                    weight [i] [j] = -weight [i] [j];         // 如果需要保持 weight [ ] [ ] 原来的值,这里需要将其还原

        }

        return sum;

    }

    struct Point{

        int r,c;

    };

    int main(){

        int i,j,m;

        freopen("in","r",stdin);

        int w[M][M];

        char c; Point pt;

        while(cin >> n >> m && (n!=0 || m!=0)){

            vector<Point> vh,vm;

            for(i=0;i<n;i++){

                getchar();

                for(j=0;j<m;j++){

                    scanf("%c",&c);

                    if(c=='H'){

                        pt.r=i; pt.c=j;

                        vh.push_back(pt);

                    }

                    if(c=='m'){

                        pt.r=i;pt.c=j;

                        vm.push_back(pt);

                    }

                }

            }

            for(i=0;i<vm.size();i++) for(j=0;j<vh.size();j++) w[i][j]=abs(vm[i].r-vh[j].r)+abs(vm[i].c-vh[j].c);

            n=vm.size();

            cout << km(false,w)<< endl;

        }

    }

    两种欧拉路

    无向图:

    #define M 45

    int used[M][M],id[M];

    void dfs(int u,vector<int> g[],vector<int> &vans){  //O(E^2)

             int j,w,v,t;

             for(j=g[u].size()-1;j>=0;j--){

                       t=v=g[u][j]; w=u;

                       if(v>w) swap(v,w);

                       if(used[v][w]!=0){

                                used[v][w]--;

                                dfs(t,g,vans);

                       }

             }

             vans.push_back(u);

    }

    有向图:

    int n,m;

    vector<int> g[M],vans;

    void dfs(int u){   //O(E^2*log(e))

             int j,t;

             Edg et;

             for(j=g[u].size()-1;j>=0;j--){

                       et.u=u; et.v=g[u][j];

                       if(mp[et]!=0){

                                mp[et]--;

                                dfs(g[u][j]);

                       }

             }

             vans.push_back(u);

    }

    【最大流】Edmonds Karp

    //求最小割集合的办法:

    //设置一个集合A, 最开始A={s},按如下方法不断扩张A:

    //1 若存在一条边(u,v), 其流量小于容量,且u属于A,则v加入A

    //2 若存在(v,u), 其流量大于0,且u属于A,则v加入A

    //A计算完毕,设B=V-A,

    //最大流对应的割集E={(u,v) | u∈A,v∈B}

    //E为割集,这是一定的

     

    //【最大流】Edmonds Karp算法求最大流,复杂度 O(V E^2)。返回最大流,输入图容量

    //矩阵g[M][M],取非零值表示有边,s为源点,t为汇点,f[M][M]返回流量矩阵。

    int f[M][M],g[M][M];

    int EdmondsKarp(int n,int s,int t){ 

             int i,j,k,c,head,tail,flow=0;

             int r[M][M];

             int prev[M],visit[M],q[M];

             for (i=1;i<=n;i++) for (j=1;j<=n;j++) {f[i][j]=0;r[i][j]=g[i][j];} //初始化流量网络和残留网络

             while (1) { //在残留网络中找到一条s到t的最短路径

                       head=tail=0;

                       memset(visit,0,sizeof(visit));

                       q[tail++]=s;

                       prev[s]=-1; visit[s]=1;

                       while(head!=tail){  //宽度优先搜索从s到t的最短路径

                                k=q[head++];

                                for (i=1;i<=n;i++)

                                         if (!visit[i] && r[k][i]>0) {

                                                   visit[i]=1;

                                                   prev[i]=k;

                                                   if (i==t) goto next;

                                                   q[tail++]=i;

                                         }

                       }

    next: 

                       if (!visit[t]) break; //流量已达到最大

                       c=99999999;

                       j=t;

                       while (j!=s) {

                                i=prev[j];

                                if (c>r[i][j]) c=r[i][j];

                                j=i;

                       }

                       //下面改进流量

                       j=t;

                       while (j!=s) {

                                i=prev[j];

                                f[i][j]+=c;

                                f[j][i]=-f[i][j];

                                r[i][j]=g[i][j]-f[i][j];

                                r[j][i]=g[j][i]-f[j][i];

                                j=i;

                       }

                       flow+=c;

                       //cout << c << endl;

             }

             return flow;

    }

    dinic

    /* dinic

    BFS+多路增广

    这个模板是OIBH上的Code_Rush的,他写的Dinic和别人的不太一样,速度更快

    O(mn^2) */

    #include<stdio.h>

    #include<list>

    #include<queue>

    #include<string.h>

    #include <vector>

    #include <iostream>

    using namespace std;

    #define M 201

    int pre[M];

    int f[M][M],g[M][M];

    bool b[M]={0};

    //g为输入的图容量矩阵,f为返回流量矩阵

    int dinic(int n,int s,int t)

    {   memset(f,0,sizeof(f));

        int ans=0;

        while(true)

        {   queue<int> q;

            fill(pre,pre+n+2,-1);

            fill(b,b+n+2,0);

            q.push(s);b[s]=1;

            while(!q.empty())

            {

                int x=q.front();q.pop();

                if(x==t)break;

                for(int i=1;i<=n;i++)

                                {

                    if(!b[i]&&f[x][i]<g[x][i])

                    {

                        pre[i]=x;

                        b[i]=1;

                        q.push(i);

                    }

                                }

            }

            if(pre[t]==-1)break;

            for(int i=1;i<=n;i++)

                       {

                if(f[i][t]<g[i][t]&&(i==s||pre[i]!=-1))

                {

                    int v,low=g[i][t]-f[i][t];

                    pre[t]=i;

                    for(v=t;pre[v]!=-1;v=pre[v])

                        low=low<g[pre[v]][v]-f[pre[v]][v]?low:g[pre[v]][v]-f[pre[v]][v];

                    if(low==0)continue;

                    for(v=t;pre[v]!=-1;v=pre[v])

                    {

                        f[pre[v]][v]+=low;

                        f[v][pre[v]]-=low;

                    }

                    ans+=low;

                }

                       }

        }

             return ans;

    int main(){

             int m,n,i,j,u,v,w;

             while(cin >> m >> n){

                       memset(g,0,sizeof(g));

                       for(i=0;i<m;i++){

                                scanf("%d%d%d",&u,&v,&w);

                                g[u][v]+=w;

                       }

                       cout << dinic(n,1,n) << endl;

             }

    }

    【最小费用最大流】Edmonds Karp对偶算法

    #define M 211

    #define LIM 99999999

    //【最小费用最大流】Edmonds Karp对偶算法,复杂度 O(V^3E^2)。返回最大流,输入图

    //容量矩阵g[M][M],费用矩阵w[M][M],取非零值表示有边,s为源点,t为汇点,f[M][M]返

    //回流量矩阵,minw返回最小费用。

    int g[M][M],w[M][M],minw,f[M][M];

    int DualityEdmondsKarp(int n,int s,int t){        

             int i,j,k,c,quit,flow=0;

             int best[M],prev[M];

             minw=0;

             for (i=1;i<=n;i++) {

                       for (j=1;j<=n;j++){

                                f[i][j]=0;

                                if (g[i][j]) {g[j][i]=0;w[j][i]=-w[i][j];}

                       }

             }

             while (1) {

                       for (i=1;i<=n;i++) best[i]=LIM;

                       best[s]=0;

                       do {

                                quit=1;

                                for (i=1;i<=n;i++){

                                         if (best[i]<LIM)

                                                   for (j=1;j<=n;j++){

                                                            if (f[i][j]<g[i][j] && best[i]+w[i][j]<best[j]){

                                                                     best[j]=best[i]+w[i][j];

                                                                     prev[j]=i;

                                                                     quit=0;

                                                            }

                                                   }

                                }

                       }while(!quit);

                       if (best[t]>=LIM) break;

                       c=LIM;

                       j=t;

                       while (j!=s) {

                                i=prev[j];

                                if (c>g[i][j]-f[i][j]) c=g[i][j]-f[i][j];

                                j=i;

                       }

                       j=t;

                       while (j!=s) {

                                i=prev[j];

                                f[i][j]+=c;

                                f[j][i]=-f[i][j];

                                j=i;

                       }

                       flow+=c; minw+=c*best[t];

             }

             return flow;

    }

    【题目1】N皇后问题(八皇后问题的扩展)

    【题目2】排球队员站位问题

    【题目3】把自然数N分解为若干个自然数之和

    【题目4】把自然数N分解为若干个自然数之积

    【题目5】马的遍历问题

    【题目6】加法分式分解

    【题目7】地图着色问题

    【题目8】在n*n的正方形中放置长为2,宽为1的长条块,

    【题目9】找迷宫的最短路径。(广度优先搜索算法)

    【题目10】火车调度问题

    【题目11】农夫过河

    【题目12】七段数码管问题

    【题目13】把1-8这8个数放入下图8个格中,要求相邻的格(横,竖,对角线)上填的数不连续.

    【题目14】在4×4的棋盘上放置8个棋,要求每一行,每一列上只能放置2个.

    【题目15】迷宫问题.求迷宫的路径.(深度优先搜索法)

    【题目16】一笔画问题

    【题目17】城市遍历问题.

    【题目18】棋子移动问题

    【题目19】求集合元素问题(1,2x+1,3X+1类)

    【题目】N皇后问题(含八皇后问题的扩展,规则同八皇后):在N*N的棋盘上,放置N个皇后,要求每一横行
    每一列,每一对角线上均只能放置一个皇后,问可能的方案及方案数。

    const max=8;

    var i,j:integer;

    a:array[1..max] of 0..max;   {放皇后数组}

    b:array[2..2*max] of boolean;  {/对角线标志数组}

    c:array[-(max-1)..max-1] of boolean; {对角线标志数组}

    col:array[1..max] of boolean;  {列标志数组}

    total:integer;        {统计总数}

    procedure output; {输出}

    var i:integer;

    begin

         write('No.':4,'[',total+1:2,']');

         for i:=1 to max do write(a[i]:3);write('     ');

         if (total+1) mod 2 =0 then  writeln;  inc(total);

    end;

    function  ok(i,dep:integer):boolean;  {判断第dep行第i列可放否}

    begin

              ok:=false;

              if ( b[i+dep]=true) and ( c[dep-i]=true) {and (a[dep]=0)} and

                          (col[i]=true) then   ok:=true

    end;

     

    procedure try(dep:integer);

    var i,j:integer;

    begin

         for i:=1 to max do    {每一行均有max种放法}

           if  ok(i,dep) then begin

               a[dep]:=i;

               b[i+dep]:=false;  {/对角线已放标志}

               c[dep-i]:=false;  {对角线已放标志}

               col[i]:=false;    {列已放标志}

               if dep=max then output

                          else try(dep+1); {递归下一层}

               a[dep]:=0;            {取走皇后,回溯}

               b[i+dep]:=true;   {恢复标志数组}

               c[dep-i]:=true;

               col[i]:=true;

           end;

    end;

    begin

         for i:=1 to max do begin a[i]:=0;col[i]:=true;end;

         for i:=2 to 2*max do b[i]:=true;

         for i:=-(max-1) to max-1 do c[i]:=true;

         total:=0;

         try(1);

         writeln('total:',total);

    end.

    【测试数据】

    n=8 八皇后问题

     No.[ 1]  1  5      8  6  3  7  2  4      No.[ 2]  1  6  8   3  7  4  2  5

     No.[ 3]  1  7      4  6  8  2  5  3      No.[ 4]  1  7  5   8  2  4  6  3

     No.[ 5]  2  4      6  8  3  1  7  5      No.[ 6]  2  5  7   1  3  8  6  4

     No.[ 7]  2  5      7  4  1  8  6  3      No.[ 8]  2  6  1   7  4  8  3  5

     No.[ 9]  2  6      8  3  1  4  7  5      No.[10]  2  7  3   6  8  5  1  4

     No.[11]  2  7      5  8  1  4  6  3      No.[12]  2  8  6   1  3  5  7  4

     No.[13]  3  1      7  5  8  2  4  6      No.[14]  3  5  2   8  1  7  4  6

     No.[15]  3  5      2  8  6  4  7  1      No.[16]  3  5  7   1  4  2  8  6

     No.[17]  3  5      8  4  1  7  2  6      No.[18]  3  6  2   5  8  1  7  4

     No.[19]  3  6      2  7  1  4  8  5      No.[20]  3  6  2   7  5  1  8  4

     No.[21]  3  6      4  1  8  5  7  2      No.[22]  3  6  4   2  8  5  7  1

     No.[23]  3  6      8  1  4  7  5  2      No.[24]  3  6  8   1  5  7  2  4

     No.[25]  3  6      8  2  4  1  7  5      No.[26]  3  7  2   8  5  1  4  6

     No.[27]  3  7      2  8  6  4  1  5      No.[28]  3  8  4   7  1  6  2  5

     No.[29]  4  1      5  8  2  7  3  6      No.[30]  4  1  5   8  6  3  7  2

     No.[31]  4  2      5  8  6  1  3  7      No.[32]  4  2  7   3  6  8  1  5

     No.[33]  4  2      7  3  6  8  5  1      No.[34]  4  2  7   5  1  8  6  3

     No.[35]  4  2      8  5  7  1  3  6      No.[36]  4  2  8   6  1  3  5  7

     No.[37]  4  6      1  5  2  8  3  7      No.[38]  4  6  8   2  7  1  3  5

     No.[39]  4  6      8  3  1  7  5  2      No.[40]  4  7  1   8  5  2  6  3

     No.[41]  4  7      3  8  2  5  1  6      No.[42]  4  7  5   2  6  1  3  8

     No.[43]  4  7      5  3  1  6  8  2      No.[44]  4  8  1   3  6  2  7  5

     No.[45]  4  8      1  5  7  2  6  3      No.[46]  4  8  5   3  1  7  2  6

     No.[47]  5  1      4  6  8  2  7  3      No.[48]  5  1  8   4  2  7  3  6

     No.[49]  5  1      8  6  3  7  2  4      No.[50]  5  2  4   6  8  3  1  7

     No.[51]  5  2      4  7  3  8  6  1      No.[52]  5  2  6   1  7  4  8  3

     No.[53]  5  2      8  1  4  7  3  6      No.[54]  5  3  1   6  8  2  4  7

     No.[55]  5  3      1  7  2  8  6  4      No.[56]  5  3  8   4  7  1  6  2

     No.[57]  5  7      1  3  8  6  4  2      No.[58]  5  7  1   4  2  8  6  3

     No.[59]  5  7      2  4  8  1  3  6      No.[60]  5  7  2   6  3  1  4  8

     No.[61]  5  7      2  6  3  1  8  4      No.[62]  5  7  4   1  3  8  6  2

     No.[63]  5  8      4  1  3  6  2  7      No.[64]  5  8  4   1  7  2  6  3

     No.[65]  6  1      5  2  8  3  7  4      No.[66]  6  2  7   1  3  5  8  4

     No.[67]  6  2      7  1  4  8  5  3      No.[68]  6  3  1   7  5  8  2  4

     No.[69]  6  3      1  8  4  2  7  5      No.[70]  6  3  1   8  5  2  4  7

     No.[71]  6  3      5  7  1  4  2  8      No.[72]  6  3  5   8  1  4  2  7

     No.[73]  6  3      7  2  4  8  1  5      No.[74]  6  3  7   2  8  5  1  4

     No.[75]  6  3      7  4  1  8  2  5      No.[76]  6  4  1   5  8  2  7  3

     No.[77]  6  4      2  8  5  7  1  3      No.[78]  6  4  7   1  3  5  2  8

     No.[79]  6  4      7  1  8  2  5  3      No.[80]  6  8  2   4  1  7  5  3

     No.[81]  7  1      3  8  6  4  2  5      No.[82]  7  2  4   1  8  5  3  6

     No.[83]  7  2      6  3  1  4  8  5      No.[84]  7  3  1   6  8  5  2  4

     No.[85]  7  3      8  2  5  1  6  4      No.[86]  7  4  2   5  8  1  3  6

     No.[87]  7  4      2  8  6  1  3  5      No.[88]  7  5  3   1  6  8  2  4

     No.[89]  8  2      4  1  7  5  3  6      No.[90]  8  2  5   3  1  7  4  6

     No.[91]  8  3      1  6  2  5  7  4      No.[92]  8  4  1   3  6  2  7  5

    total:92

    对于N皇后:

    ┏━━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┓

    ┃皇后 N│ 4  │ 5  │ 6  │ 7 │ 8  │ 9  │ 10 ┃

    ┠───┼──┼──┼──┼──┼──┼──┼──┨

    ┃方案数│ 2  │ 10 │ 4  │ 40 │ 92 │352 │724 ┃

    ┗━━━┷━━┷━━┷━━┷━━┷━━┷━━┷━━┛

    【题目】排球队员站位问题

    ┏━━━━━━━━┓图为排球场的平面图,其中一、二、三、四、五、六为位置编号,

    ┃        ┃二、三、四号位置为前排,一、六、五号位为后排。某队比赛时,

    ┃        ┃一、四号位放主攻手,二、五号位放二传手,三、六号位放副攻

    ┠──┬──┬──┨手。队员所穿球衣分别为1,2,3,4,5,6号,但每个队

    ┃ 四 │ 三 │ 二 ┃员的球衣都与他们的站位号不同。已知1号、6号队员不在后排,

    ┠──┼──┼──┨2号、3号队员不是二传手,3号、4号队员不在同一排,5号、

    ┃ 五 │ 六 │ 一 ┃6号队员不是副攻手。

    ┗━━┷━━┷━━┛ 编程求每个队员的站位情况。

    【算法分析】本题可用一般的穷举法得出答案。也可用回溯法。以下为回溯解法。

    【参考程序】

    type sset=set of 1..6;

    var   a:array[1..6]of 1..6;

          d:array[1..6]of sset;

          i:integer;

    procedure output; {输出}

    begin

                     if not( (a[3]in [2,3,4])= (a[4] in[2,3,4])) then

                     begin                                       { 3,4号队员不在同一排 }

                          write('number:');for i:=1 to 6 do write(i:8);writeln;

                          write('weizhi:');for i:=1 to 6 do write(a[i]:8);writeln;

                     end;

    end;

     

    procedure try(i:integer;s:sset); {递归过程  i:第i个人,s:哪些位置已安排人了}

    var

       j,k:integer;

    begin

         for j:=1 to 6 do begin    {每个人都有可能站1-6这6个位置}

                 if (j in d[i]) and not(j in s) then begin

                   {j不在d[i]中,则表明第i号人不能站j位. j如在s集合中,表明j位已排人了}

                    a[i]:=j;                    {第 i 人可以站 j 位}

                    if i<6 then try(i+1,s+[j])   {未安排妥,则继续排下去}

                             else  output;     {6个人都安排完,则输出}

                  end;

           end;

    end;

    begin

         for i:=1 to 6 do d[i]:=[1..6]-[i];       {每个人的站位都与球衣的号码不同}

         d[1]:=d[1]-[1,5,6];

         d[6]:=d[6]-[1,5,6];     {1,6号队员不在后排}

         d[2]:=d[2]-[2,5];

         d[3]:=d[3]-[2,5];              {2,3号队员不是二传手}

         d[5]:=d[5]-[3,6];

         d[6]:=d[6]-[3,6];              {5,6号队员不是副攻手}

         try(1,[]);

    end.

    【题目】把自然数N分解为若干个自然数之和。

    【参考答案】

                         n     │ total 
                         5     │   7

                         6     │  11

                         7     │  15

                        10     │  42

                        100    │  190569291

    【参考程序】

    var n:byte; num:array[0..255] of byte;   total:word;

    procedure output(dep:byte);

    var j:byte;

    begin

         for j:=1 to dep do write(num[j]:3);writeln;    inc(total);

    end;

    procedure find(n,dep:byte);  {N:待分解的数,DEP:深度}

      var i,j,rest:byte;

      begin

         for i:=1 to n do            {每一位从N到1去试}

          if num[dep-1]<=i then   {保证选用的数大于前一位}

           begin

               num[dep]:=i;

               rest:=n - i;             {剩余的数进行下一次递归调用}

               if (rest>0) then begin   find(rest,dep+1);end

                             else if rest=0 then output(dep);{刚好相等则输出}

               num[dep]:=0;

           end;

      end;

     

    begin  {主程序}

       writeln('input n:');readln(n);

       fillchar(num,sizeof(num),0);

       total:=0; num[0]:=0;

       find(n,1);

       writeln('sum=',total);

    end.

    【题目】把自然数N分解为若干个自然数之积。

    【参考程序】

    var  path :array[1..1000] of integer;

         total,n:integer;

    procedure find(k,sum,dep:integer);       {K:}

    var b,d:Integer;

    begin

         if sum=n then                  {积等于N}

          begin

              write(n,'=',path[1]);

              for d:=2 to dep-1 do write('*',path[d]);

              writeln;inc(total);

              exit;

          end;

        if sum>n then exit;                  {累积大于N}

        for b:= trunc(n/sum)+1 downto k do   {每一种可能都去试}

              begin

                     path[dep]:=b;

                     find(b,sum*b,dep+1);

              end;

    end;

    begin

    readln(n); total:=0;

    find(2,1,1);writeln('total:',total);

    readln;

    end.

    【题目】马的遍历问题。在N*M的棋盘中,马只能走日字。马从位置(x,y)处出发,把

              棋盘的每一格都走一次,且只走一次。找出所有路径。

    【参考程序】 {深度优先搜索法}

    const n=5;m=4;

    fx:array[1..8,1..2]of -2..2=((1,2),(2,1),(2,-1),(1,-2),(-1,-2),(-2,-1),

                                        (-2,1),(-1,2));  {八个方向增量}

    var

      dep,i:byte; x,y:byte;

      cont:integer;            {统计总数}

      a:array[1..n,1..m]of byte;   {记录走法数组}

    procedure output; {输出,并统计总数}

    var x,y:byte;

    begin

        cont:=cont+1;  writeln;

        writeln('count=',cont);

        for y:=1 to n do  begin

              for x:=1 to m do write(a[y,x]:3);  writeln;

        end;     {      readln; halt;}

    end;

    procedure find(y,x,dep:byte);

    var i,xx,yy:integer;

    begin

        for i:=1 to 8 do

           begin

           xx:=x+fx[i,1];yy:=y+fx[i,2];  {加上方向增量,形成新的坐标}

              if ((xx in [1..m])and(yy in [1..n]))and(a[yy,xx]=0) then

                              {判断新坐标是否出界,是否已走过?}

                begin

                  a[yy,xx]:=dep;         {走向新的坐标}

                  if (dep=n*m)   then output

                                       else find(yy,xx,dep+1); {从新坐标出发,递归下一层}

                  a[yy,xx]:=0     {回溯,恢复未走标志}

                end;

          end;

    end;

    begin

      cont:=0;

      fillchar(a,sizeof(a),0);

      dep:=1;

      writeln('input y,x');readln(y,x);

    { x:=1;y:=1;}

      if (y>n) or(x>m) then begin writeln('x,y error!');halt;end;

      a[y,x]:=1;

      find(y,x,2);

     

      if cont=0 then writeln('No answer!') else write('The End!');

      readln;

    end.

    【题目】加法分式分解。如:1/2=1/4+1/4.找出所有方案。

              输入:N  M        N为要分解的分数的分母

                                   M为分解成多少项

    【参考程序】

    program fenshifenjie;

    const  nums=5;

    var

       t,m,dep:integer;

       n,maxold,max,j:longint;

       path:array[0..nums] of longint;

       maxok,p:boolean;

       sum,sum2:real;

    procedure print;

    var i:integer;

    begin

                t:=t+1;

                if maxok=true then begin maxold:=path[m];maxok:=false;end;

                write ('NO.',t);

                for i:=1 to m do write(' ',path[i]:4); writeln;

                if path[1]=path[m] then begin writeln('Ok!   total:',t:4);readln;halt;end;

    end;

    procedure input;

    begin

                writeln ('input N:'); readln(n);

                writeln ('input M(M<=',nums:1,'):'); readln(m);

                if (n<=0) or (m<=0) or (m>4) or (n>maxlongint)

                           then begin writeln('Invalid Input!');readln;halt;end;

    end;

    function sum1(ab:integer):real;

    var a,b,c,d,s1,s2:real;

        i:integer;

    begin

               if ab=1  then

                    sum1:=1/path[1]

               else

                    begin

                          a:=path[1];

                          b:=1         ;

                          c:=path[2];

                          d:=1;

                          for i:=1 to ab-1 do

                               begin

                                     s2:=(c*b+a*d);

                                     s1:=(a*c);

                                     a:=s1;

                                     b:=s2;

                                     c:=path[i+2];

                               end;

                          sum1:=s2/s1;

                     end;

    end;

    procedure back;

    begin

                dep:=dep-1;

                if dep<=m-2 then max:=maxold;

                sum:=sum-1/path[dep];

                j:=path[dep];

    end;

    procedure find;

    begin

       repeat

               dep:=dep+1;

               j:=path[dep-1]-1;

               p:=false;

                 repeat

                  j:=j+1;

                  if (dep<>m) and (j<=max) then

                     if (sum+1/j) >=1/n then p:=false

                             else  begin

                                      p:=true;

                                      path[dep]:=j;

                                      sum:=sum+1/path[dep];

                                      end

                     else if j>max then back;

                  if dep=m then begin

                     path[dep]:=j;

                     sum2:=sum1(m);

                     if (sum2)>1/n then p:=false;

                     if (sum2)=1/n then begin     print;

                                                           max:=j;

                                                           back;

                                                           end;

                     if (sum2<1/n) then back;

                     if (j>=max)   then back;

                     end;

          until p

       until dep=0;

    end;

    begin

         INPUT;

         maxok:=true;

         for t:=0 to m do  path[t]:=n;

         dep:=0; t:=0; sum:=0;

         max:=maxlongint;

         find;

         readln;

    end.

    【题目】地图着色问题

    【参考程序1】

    const lin:array[1..12,1..12] of 0..1  {区域相邻数组,1表示相邻}

          =((0,1,1,1,1,1,0,0,0,0,0,0),

              (1,0,1,0,0,1,1,1,0,0,0,0),

              (1,1,0,1,0,0,0,1,1,0,0,0),

              (1,0,1,0,1,0,1,0,1,1,0,0),

              (1,0,0,1,0,1,0,0,0,1,1,0),

              (1,1,0,0,1,0,1,0,0,0,1,0),

              (0,1,0,0,0,1,0,1,0,0,1,1),

              (0,1,1,0,0,0,1,0,1,0,0,1),

              (0,0,1,1,0,0,0,1,0,1,0,1),

              (0,0,0,1,1,0,0,0,1,0,1,1),

              (0,0,0,0,1,1,1,0,0,1,0,1),

              (0,0,0,0,0,0,1,1,1,1,1,1));

    var  color:array[1..12] of byte;   {color数组放已填的颜色}

         total:integer;

    function ok(dep,i:byte):boolean;  {判断选用色i是否可用}

    var k:byte;                                {条件:相邻的区域颜色不能相同}

    begin

      for k:=1 to dep do

          if (lin[dep,k]=1) and (i=color[k]) then begin ok:=false;exit;end;

      ok:=true;

    end;

     

    procedure output;     {输出}

    var k:byte;

    begin

      for k:=1 to 12 do write(color[k],' ');writeln;

      total:=total+1;

    end;

    procedure find(dep:byte); {参数dep:当前正在填的层数}

    var i:byte;

    begin

      for i:=1 to 4 do begin       {每个区域都可能是1-4种颜色}

       if ok(dep,i) then  begin

                  color[dep]:=i;

                  if dep=12 then output else find(dep+1);

                  color[dep]:=0;     {恢复初始状态,以便下一次搜索}

                  end;

      end;

    end;

    begin

     total:=0; {总数初始化}

     fillchar(color,sizeof(color),0);

     find(1);

     writeln('total:=',total);

    end.

    【参考程序2】

    const       {lin数组:代表区域相邻情况}

     lin:array[1..12] of set of  1..12 =

               ([2,3,4,5,6],[1,3,6,7,8],[1,2,4,8,9],[1,3,5,9,10],[1,4,6,10,11],

                [1,2,5,7,11],[12,8,11,6,2],[12,9,7,2,3],[12,8,10,3,4],

                [12,9,11,4,5],[12,7,10,5,6],[7,8,9,10,11]);

    color:array[1..4] of char=('r','y','b','g');

    var a:array[1..12] of byte; {因有12个区域,故a数组下标为1-12}

        total:integer;

    function ok(dep,i:integer):boolean; {判断第dep块区域是否可填第i种色}

    var j:integer;      { j 为什么设成局部变量?}

    begin

         ok:=true;

         for j:=1 to 12 do

               if (j in lin[dep]) and (a[j]=i) then ok:=false;

    end;

     

    procedure output; {输出过程}

     var j:integer;  { j 为什么设成局部变量?}

     begin

                inc(total);  {方案总数加1}

                write(total:4); {输出一种方案}

                for j:=1 to 12 do write(color[a[j]]:2);writeln;

    end;

    procedure find(dep:byte);

    var i:byte; { i 为什么设成局部变量?}

    begin

          for i:=1 to 4 do              {每一区域均可从4种颜色中选一}

                begin

                 if ok(dep,i) then begin    {可填该色}

                    a[dep]:=i;   {第dep块区域填第i种颜色}

                    if (dep=12) then output  {填完12个区域}

                                     else find(dep+1); {未填完}

                     a[dep]:=0;  {取消第dep块区域已填的颜色}

                    end;

                end;

    end;

    begin {主程序}

         fillchar(a,sizeof(a),0);  {记得要给变量赋初值!}

         total:=0;

         find(1);

         writeln('End.');

    end.

    【题目】在n*n的正方形中放置长为2,宽为1的长条块,问放置方案如何

    【参考程序1】

    const n=4;

    var  k,u,v,result:integer;

         a:array[1..n,1..n]of char;

    procedure printf; {输出}

      begin

        result:=result+1;          {方案总数加1}

        writeln('--- ',result,' ---');

        for v:=1 to n do   begin

              for u:=1 to n do write(a[u,v]); writeln end; writeln;

      end;

     

    procedure try;      {填放长条块}

      var     i,j,x,y:integer;  full:boolean;

      begin

        full:=true;

        if k<>trunc(n*n/2) then full:=false;{测试是否已放满}

        if full then printf;   {放满则可输出}

        if not full then  begin    {未满}

               x:=0;y:=1;   {以下先搜索未放置的第一个空位置}

               repeat

                 x:=x+1;

                 if x>n then begin x:=1;y:=y+1 end

               until a[x,y]=' ';

        {找到后,分两种情况讨论}

               if a[x+1,y]=' ' then   begin   {第一种情况:横向放置长条块}

                   k:=k+1;                             {记录已放的长条数}

                   a[x,y]:=chr(k+ord('@'));   {放置}

                   a[x+1,y]:=chr(k+ord('@'));

                   try;                      {递归找下一个空位置放}

                   k:=k-1;

                   a[x,y]:=' ';               {回溯,恢复原状}

                   a[x+1,y]:=' '

               end;

               if a[x,y+1]=' ' then   begin    {第二种情况:竖向放置长条块}

                   k:=k+1;                             {记录已放的长条数}

                   a[x,y]:=chr(k+ord('0'));    {放置}

                   a[x,y+1]:=chr(k+ord('0'));

                   try;                      {递归找下一个空位置放}

                   k:=k-1;

                   a[x,y]:=' ';                {回溯,恢复原状}

                   a[x,y+1]:=' '

               end;

        end;

      end;

    begin     {主程序}

      fillchar(a,sizeof(a),' ');  {记录放置情况的字符数组,初始值为空格}

      result:=0; k:=0;  {k记录已放的块数,如果k=n*n/2,则说明已放满}

      try;    {每找到一个空位置,把长条块分别横放和竖放试验}

    end.

     

    【参考程序2】

    const dai:array [1..2,1..2]of integer=((0,1),(1,0));

    type node=record

                        w,f:integer;

                        end;

    var a:array[1..20,1..20]of integer;

    path:array[0..200]of node;

    s,m,n,nn,i,j,x,y,dx,dy,dep:integer;

    p,px:boolean;

    procedure inputn;

    begin

    { write('input n');readln(n);}

     n:=4;

     nn:=n*n;m:=nn div 2;

    end;

    procedure print;

    var i,j:integer;

    begin

     inc(s);writeln('no',s);

     for i:=1 to n do begin

       for j:=1 to n do

         write(a[i,j]:3);writeln;

         end;

         writeln;

    end;

    function fg(h,v:integer):boolean;

    var p:boolean;

    begin

       p:=false;

       if (h<=n) and (v<=n) then

                                   if a[h,v]=0 then p:=true;

       fg:=p;

      end;

    procedure back;

     begin

       dep:=dep-1;

       if dep=0 then begin p:=true ;px:=true;end

          else begin

              i:=path[dep].w;j:=path[dep].f;

              x:=((i-1)div n )+1;y:=i mod n;

              if y=0 then y:=n;

              dx:=x+dai[j,1];dy:=y+dai[j,2];

              a[x,y]:=0;a[dx,dy]:=0;

              end;

    end;

    begin

     inputn;

     s:=0;

     fillchar(a,sizeof(a),0);

     x:=0;y:=0;dep:=0;

     path[0].w:=0;path[0].f:=0;

     repeat

       dep:=dep+1;

       i:=path[dep-1].w;

       repeat

        i:=i+1;x:=((i-1)div n)+1;

        y:=i mod n;if y=0 then y:=n;

        px:=false;

        if fg(x,y)

         then begin

         j:=0;p:=false;

         repeat

         inc(j);

         dx:=x+dai[j,1];dy:=y+dai[j,2];

         if fg(dx,dy) and (j<=2) then begin

           a[x,y]:=dep;a[dx,dy]:=dep;

           path[dep].w:=i;path[dep].f:=j;

           if dep=m then begin print;dep:=m+1;back;end

                         else begin p:=true;px:=true;end;

                         end

           else if j>=2 then back

                            else p:=false;

           until p;

           end

           else if i>=nn then back

                          else px:=false;

         until px;

        until dep=0;

        readln;

     end.

    【题目】找迷宫的最短路径。(广度优先搜索算法)

    【参考程序】

    uses crt;

    const

    migong:array  [1..5,1..5] of integer=((0,0,-1,0,0), (0,-1,0,0,-1),

                                   (0,0,0,0,0), (0,-1,0,0,0),  (-1,0,0,-1,0));

                                   {迷宫数组}

    fangxiang:array  [1..4,1..2] of -1..1=((1,0),(0,1),(-1,0),(0,-1));

                                                       {方向增量数组}

    type node=record

                   lastx:integer;  {上一位置坐标}

                   lasty:integer;

                   nowx:integer;   {当前位置坐标}

                   nowy:integer;

                   pre:byte;          {本结点由哪一步扩展而来}

                   dep:byte;          {本结点是走到第几步产生的}

                end;

    var

        lujing:array[1..25] of node;   {记录走法数组}

        closed,open,x,y,r:integer;

    procedure output;

    var i,j:integer;

    begin

      for i:=1 to 5 do  begin

        for j:=1 to 5 do

          write(migong[i,j]:4); writeln;end;

      i:=open;

      repeat

         with lujing[i] do

               write(nowy:2,',',nowx:2,' <--');

         i:=lujing[i].pre;

      until lujing[i].pre=0;

         with lujing[i] do

               write(nowy:2,',',nowx:2);

    end;

    begin

      clrscr;

      with lujing[1] do begin  {初始化第一步}

         lastx:=0;      lasty:=0; nowx:=1;nowy:=1;pre:=0;dep:=1;end;

      closed:=0;open:=1;migong[1,1]:=1;

      repeat

        inc(closed); {队列首指针加1,取下一结点}

        for r:=1 to 4 do begin     {以4个方向扩展当前结点}

          x:=lujing[closed].nowx+fangxiang[r,1]; {扩展形成新的坐标值}

          y:=lujing[closed].nowy+fangxiang[r,2];

          if not ((x>5)or(y>5) or (x<1) or (y<1) or (migong[y,x]<>0)) then begin

                                                       {未出界,未走过则可视为新的结点}

                    inc(open);   {队列尾指针加1}

                    with lujing[open] do begin  {记录新的结点数据}

                        nowx:=x; nowy:=y;

                        lastx:=lujing[closed].nowx;{新结点由哪个坐标扩展而来}

                        lasty:=lujing[closed].nowy;

                        dep:=lujing[closed].dep+1; {新结点走到第几步}

                        pre:=closed;                      {新结点由哪个结点扩展而来}

                    end;

                    migong[y,x]:=lujing[closed].dep+1;  {当前结点的覆盖范围}

                    if (x=5) and (y=5) then begin  {输出找到的第一种方案}

                                     writeln('ok,thats all right');output;halt;end;

          end;

        end;

      until closed>=open; {直到首指针大于等于尾指针,即所有结点已扩展完}

    end.

    【题目】火车调度问题

    【参考程序】

    const max=10;

    type shuzu=array[1..max] of 0..max;

    var   stack,exitout:shuzu;

          n,total:integer;

    procedure output(exitout:shuzu);

    var i:integer;

    begin

         for i:=1 to n do write(exitout[i]:2);writeln;

         inc(total);

    end;

    procedure find(dep,have,rest,exit_weizhi:integer;stack,exitout:shuzu);

    {dep:步数,have:入口处有多少辆车;rest:车站中有多少车;}

    {exit_weizhi:从车站开出后,排在出口处的位置;}

    {stack:车站中车辆情况数组;exitout:出口处车辆情况数组}

    var i:integer;

    begin  {分入站,出站两种情况讨论}

                  if have>0 then begin    {还有车未入站}

                     stack[rest+1]:=n+1-have;   {入站}

                     if dep=2*n then output(exitout)

                          else find(dep+1,have-1,rest+1,exit_weizhi,stack,exitout);

                  end;

                  if rest>0 then begin    {还有车可出站}

                     exitout[exit_weizhi+1]:=stack[rest];   {出站}

                     if dep=2*n then output(exitout)   {经过2n步后,输出一种方案}

                          else find(dep+1,have,rest-1,exit_weizhi+1,stack,exitout);

                 end;

    end;

     

    begin

         writeln('input n:');

         readln(n);

         fillchar(stack,sizeof(stack),0);

         fillchar(exitout,sizeof(exitout),0);

         total:=0;

         find(1,n,0,0,stack,exitout);

         writeln('total:',total);

         readln;

    end.

    【解法2】用穷举二进制数串的方法完成.

    uses crt;

    var i,n,m,t:integer;

        a,s,c:array[1..1000] of integer;

    procedure test;

    var t1,t2,k:integer;

        notok:boolean;

    begin

         t1:=0;k:=0;t2:=0;

         i:=0;

         notok:=false;

         repeat   {二进制数串中,0表示出栈,1表示入栈}

               i:=i+1; {数串中第I位}

               if a[i]=1 then begin {第I位为1,则表示车要入栈}

                  inc(k); {栈中车数}

                  inc(t1); {入栈记录,T1为栈指针,S为栈数组}

                  s[t1]:=k;

                end

               else {第I位为0,车要出栈}

                 if t1<1 then notok:=true {已经无车可出,当然NOT_OK了}

                            else begin inc(t2);c[t2]:=s[t1];dec(t1);end;

                           {栈中有车,出栈,放到C数组中去,T2为C的指针,栈指针T1下调1}

         until (i=2*n) or notok; {整个数串均已判完,或中途出现不OK的情况}

         if (t1=0) and not notok then begin  {该数串符合出入栈的规律则输出}

            inc(m);write('[',m,']');

            for i:=1 to t2 do write(c[i]:2);

            writeln;

         end;

    end;

    begin

         clrscr; write('N=');readln(n);

         m:=0;

         for i:=1 to 2*n do a[i]:=0; {

         repeat {循环产生N位二进制数串}

               test;   {判断该数串是否符合车出入栈的规律}

               t:=2*n;

               a[t]:=a[t]+1; {产生下一个二进制数串}

               while (t>1) and (a[t]>1) do begin

                     a[t]:=0;dec(t);a[t]:=a[t]+1;

               end;

         until a[1]=2;

         readln;

    end.

    N:       4        6        7         8

    TOTAL:  14       132      429       1430

    【题目】农夫过河。一个农夫带着一只狼,一只羊和一些菜过河。河边只有一条一船,由

              于船太小,只能装下农夫和他的一样东西。在无人看管的情况下,狼要吃羊,羊

              要吃菜,请问农夫如何才能使三样东西平安过河。

    【算法分析】

        将问题数字化。用1代表狼,2代表羊,3代表菜。则在河某一边物体的分布有以下

    8种情况。

    ┏━━━━┯━┯━━━━━┯━━━━━━━━┯━━━┓

    ┃物体个数│0│    1           │         2         │    3  ┃

    ┠────┼─┼─┬─┬─┼──┬──┬──┼───┨

    ┃分布情况│0│1│2│3│1,2 │1,3 │2,3 │1,2,3 ┃

    ┠────┼─┼─┼─┼─┼──┼──┼──┼───┨

    ┃代码之和│0│1│2│3│3 │ 4 │ 5 │      6  ┃

    ┠────┼─┼─┼─┼─┼──┼──┼──┼───┨

    ┃是否相克│  │  │  │  │相克│    │相克│         ┃

    ┗━━━━┷━┷━┷━┷━┷━━┷━━┷━━┷━━━┛

    当(两物体在一起而且)代码和为3或5时,必然是相克物体在一起的情况。

    【参考程序】

    const

         wt:array[0..3]of string[5]=('     ', 'WOLF ','SHEEP','LEAVE');

    var left,right:array[1..3] of integer ;

        what,i,total,left_rest,right_rest:integer;

    procedure print_left; {输出左岸的物体}

    var i:integer;

    begin

         total:=total+1;

         write('(',total,')');  {第几次渡河}

         for i:=1 to 3 do          write(wt[left[i]]);

         write('|',' ':4);

    end;

    procedure print_right;{输出右岸的物体}

    var i:integer;

    begin

         write(' ':4,'|');

         for i:=1 to 3 do if right[i]<>0 then write(wt[right[i]]);

         writeln;

    end;

    procedure print_back(who:integer);  {右岸矛盾时,需从右岸捎物体→左岸}

    var i:integer;

    begin

         for i:=1 to 3 do begin

               if not ((i=who) or (right[i]=0)) then begin

               {要捎回左岸的物体不会时刚刚从左岸带来的物体,也不会是不在右岸的物体}

                     what:=right[i];

                     right[i]:=0;

               print_left;  {输出返回过程}

               write('<-',wt[i]);

               print_right;

               left[i]:=what;  {物体到达左岸}

               end;

         end;

    end;

    begin

         total:=0;

         for i:=1 to 3 do begin  left[i]:=i; right[i]:=0;end;

         repeat

           for i:=1 to 3 do    {共有3种物体}

               if left[i]<>0 then  {第I种物体在左岸}

                begin

                  what:=left[i];left[i]:=0;  {what:放置将要过河的物体编号}

                  left_rest:=left[1]+left[2]+left[3];  {求左岸剩余的物体编号总和}

                  if (left_rest=3) or (left_rest=5) then left[i]:=what

                                   {假如左岸矛盾,则不能带第I种过河,尝试下一物体}

                     else         {否则可带过河}

                            begin print_left;          {输出过河过程}

                                     write('->',wt[i]);

                                     print_right;

                                     right[i]:=what;  {物体到达右岸}

                                     if left_rest=0 then halt;  {左岸物体已悉数过河}

                                     right_rest:=right[1]+right[2]+right[3];

                                                             {求右岸剩余的物体编号总和}

                                    if (right_rest=3)or(right_rest=5) then print_back(i)

                                                              {右岸有矛盾,要捎物体回左岸}

                                        else begin print_left;  {右岸有矛盾,空手回左岸}

                                                       write('<-',' ':5);

                                                       print_right;

                                               end;

                            end;

                end;

           until false;  {不断往返}

    end.

    【题目】七段数码管问题。从一个数字变化到其相邻的数字只需要通过某些段(数目不限)

        1          或拿走某些段(数目不限)来实现.但不允许既增加段又拿起段.

      ┏━┓     例如:3可以变到9,也可以变到1

     6┃ 7┃2 ━┓     ┏━┓        ━┓      ┃

      ┣━┫     ┃     ┃  ┃          ┃      ┃

     5┃  ┃3 ━┫ → ┗━┫          ━┫  →  ┃

      ┗━┛     ┃          ┃          ┃      ┃

        4               ━┛        ━┛        ━┛      ┃

     

    要求:(1)判断从某一数字可以变到其它九个数字中的哪几个.

         (2)找出一种排列这十个数字的方案,便这样组成的十位数数值最小.

    type kkk=set of 0..9;

    const a:array[-1..9] of set of 1..7

              =([5,6],[1,2,3,4,5,6],[2,3],[1,2,4,5,7],[1,2,3,4,7],[2,3,6,7],

                [1,3,4,6,7],[1,3,4,5,6,7],[1,2,3],[1,2,3,4,5,6,7],[1,2,3,4,6,7]);

    var

       i,j:integer;

       b:array[-2..9] of set of 0..9;

    procedure number(p:string;s,l:integer;k:kkk);

      {P:生成的数;s:用了几个数字;i:前一个是哪个数字;k:可用的数字}

    var i:integer;

    begin

         for i:=0 to 9 do

               if (i in k) and ( i in b[l]) then begin

               {数字i未用过,且i可由前一个采用的数字变化而来}

                  if s=10 then begin writeln('Min:',p,i);readln;halt;end

                     else number(p+chr(48+i),s+1,i,k-[i]);

               end;

    end;

     

    begin

         for i:=1 to 9 do b[i]:=[];

         b[-2]:=[0..9];

         for i:=-1 to 8 do

               for j:=i+1 to 9 do

                   if (a[i]<=a[j]) or (a[j]<=a[i]) then begin

                        b[i]:=b[i]+[j];

                        b[j]:=b[j]+[abs(i)];

                   end;

               b[1]:=b[1]+b[-1];

         for i:=0 to 9 do begin

               write(i,' may turn to :');

               for j:=0 to 9 do if  j in b[i] then write(j,' ');

               writeln;

         end;

         number('',1,-2,[0..9]);

    end.

    【题目】 把1-8这8个数放入下图8个格中,要求相邻的格(横,竖,对角线)上填的数不连续.

        ┌─┐

        │①│

    ┌─┼─┼─┐

    │②│③│④│

    ├─┼─┼─┤

    │⑤│⑥│⑦│

    └─┼─┼─┘

        │⑧│

        └─┘

    【参考程序】

    const lin:array[1..8] of set of  1..8 =

               ([3,2,4],[1,6,3,5],[5,7,1,2,4,6],[1,6,3,7],

               [3,8,2,6],[2,4,3,5,7,8],[3,8,4,6],[5,7,6]);

    var a:array[1..8] of integer;

        total,i:integer; had:set of 1..8;

    function ok(dep,i:integer):boolean; {判断是否能在第dep格放数字i}

    var j:integer;

    begin

         ok:=true;

         for j:=1 to 8 do          {相邻且连续则不行}

               if (j in lin[dep]) and (abs(i-a[j])=1) then ok:=false;

         if i in had then ok:=false; {已用过的也不行}

    end;

     

    procedure output;    {输出一种方案}

     var j:integer;

     begin

                inc(total);       write(total,':');

                for j:=1 to 8 do write(a[j]:2);writeln;

    end;

    procedure find(dep:byte);

    var i:byte;

    begin

                 for i:=1 to 8 do   begin  {每一格可能放1-8这8个数字中的一个}

                        if ok(dep,i) then begin

                           a[dep]:=i;  {把i放入格中}

                           had:=had+[i];  {设置已放过标志}

                           if (dep=8) then output

                                          else find(dep+1);

                            a[dep]:=10;   {回溯,恢复原状态}

                            had:=had-[i];

                        end;

                 end;

    end;

    begin

         fillchar(a,sizeof(a),10);

         total:=0; had:=[];

         find(1);

         writeln('End.');

    end.

    【题目】 在4×4的棋盘上放置8个棋,要求每一行,每一列上只能放置2个.

    【参考程序1】

    算法:8个棋子,填8次.深度为8.注意判断是否能放棋子时,两个两个为一行.

    var a:array[1..8] of 0..4;

        line,bz:array[1..4] of 0..2; {line数组:每行已放多少个的计数器}

                                              {bz数组:  每列已放多少个的计数器}

        total:integer;

    procedure output; {输出}

    var i:integer;

    begin

         inc(total);  write(total,':   ');

         for i:=1 to 8  do write(a[i]);  writeln;

    end;

    function ok(dep,i:integer):boolean;

    begin

     ok:=true;

     if dep mod 2 =0 then  {假如是某一行的第2个,其位置必定要在第1个之后}

        if (i<=a[dep-1])  then ok:=false;

     if (bz[i]=2) or(line[dep div 2]=2) then ok:=false;

                         {某行或某列已放满2个}

    end;

    procedure find(dep:integer);

    var i:integer;

    begin

         for i:=1 to 4 do begin

               if ok(dep,i) then   begin

                  a[dep]:=i; {放在dep行i列}

                  inc(bz[i]);        {某一列记数器加1}

                  inc(line[dep div 2]);  {某一行记数器加1}

                  if dep=8 then output else find(dep+1);

                  dec(bz[i]);      {回溯}

                  dec(line[dep div 2]);

                  a[dep]:=0;

               end;

         end;

    end;

    begin

         total:=0; fillchar(a,sizeof(a),0); fillchar(bz,sizeof(bz),0);

         find(1);

    end.

    【参考程序2】

    算法:某一行的放法可能性是(1,2格),(1,3格),(1,4格)....共6种放法

    const

    fa:array[1..6] of array[1..2]of 1..4=((1,2),(1,3),(1,4),(2,3),(2,4),(3,4));

                                             {六种可能放法的行坐标}

    var

     a:array[1..8] of 0..4;

     bz:array[1..4] of 0..2; {列放了多少个的记数器}

     total:integer;

    procedure output;

    var i:integer;

    begin

         inc(total);

         write(total,':   ');

         for i:=1 to 8  do write(a[i]);

         writeln;

    end;

    function ok(dep,i:integer):boolean;

    begin

     ok:=true;  {判断现在的放法中,相应的两列是否已放够2个}

     if (bz[fa[i,1]]=2) or (bz[fa[i,2]]=2) then ok:=false;

    end;

    procedure find(dep:integer);

    var i:integer;

    begin

         for i:=1 to 6 do begin  {共有6种可能放法}

               if ok(dep,i) then   begin

                  a[(dep-1)*2+1]:=fa[i,1];{一次连续放置2个}

                  a[(dep-1)*2+2]:=fa[i,2];

                  inc(bz[fa[i,1]]);               {相应的两列,记数器均加1}

                  inc(bz[fa[i,2]]);

                  if dep=4 then output else find(dep+1);

                  dec(bz[fa[i,1]]);                {回溯}

                  dec(bz[fa[i,2]]);

                  a[(dep-1)*2+1]:=0;

                  a[(dep-1)*2+2]:=0;

               end;

         end;

    end;

    begin

         total:=0;      fillchar(a,sizeof(a),0);    fillchar(bz,sizeof(bz),0);

         find(1);

    end.

    【题目】迷宫问题.求迷宫的路径.(深度优先搜索法)

    【参考程序1】

    const

         Road:array[1..8,1..8]of 0..3=((1,0,0,0,0,0,0,0),

                                                (0,1,1,1,1,0,1,0),

                                                (0,0,0,0,1,0,1,0),

                                                (0,1,0,0,0,0,1,0),

                                                (0,1,0,1,1,0,1,0),

                                                (0,1,0,0,0,0,1,1),

                                                (0,1,0,0,1,0,0,0),

                                                (0,1,1,1,1,1,1,0)); {迷宫数组}

      FangXiang:array[1..4,1..2]of -1..1=((1,0),(0,1),(-1,0),(0,-1));{四个移动方向}

      WayIn:array[1..2]of byte=(1,1);        {入口坐标}

      WayOut:array[1..2]of byte=(8,8);       {出口坐标}

    Var i,j,Total:integer;

    Procedure Output;

    var i,j:integer;

    Begin

         For i:=1 to 8 do begin

               for j:=1 to 8 do begin

                   if Road[i,j]=1 then write(#219);       {1:墙}

                   if Road[i,j]=2 then write(' ');       {2:曾走过但不通的路}

                   if Road[i,j]=3 then write(#03) ;       {3:沿途走过的畅通的路}

                   if Road[i,j]=0 then write(' ') ;      {0:原本就可行的路}

               end;  writeln;

         end; inc(total);  {统计总数}   readln;

    end;

    Function Ok(x,y,i:byte):boolean;  {判断坐标(X,Y)在第I个方向上是否可行}

    Var NewX,NewY:shortint;

    Begin

         Ok:=True;

         Newx:=x+FangXiang[i,1];

         Newy:=y+FangXiang[i,2];

         If not((NewX in [1..8]) and (NewY in [1..8])) then Ok:=False;  {超界?}

         If Road[NewX,NewY]=3 then ok:=false;          {是否已走过的路?}

         If Road[NewX,NewY]=1 then ok:=false;          {是否墙?}

    End;

    Procedure Howgo(x,y:integer);

    Var i,NewX,NewY:integer;

    Begin

         For i:=1 to 4 do Begin              {每一步均有4个方向可选择}

               If Ok(x,y,i) then Begin       {判断某一方向是否可前进}

                  Newx:=x+FangXiang[i,1];    {前进,产生新的坐标}

                  Newy:=y+FangXiang[i,2];

                  Road[Newx,Newy]:=3;         {来到新位置后,设置已走过标志}

                  If (NewX=WayOut[1]) and(NewY=WayOut[2]) Then Output

                                   Else Howgo(Newx,NewY); {如到出口则输出,否则下一步递归}

                  Road[Newx,Newy]:=2;         {堵死某一方向,不让再走,以免打转}

               end;

         end;

    End;

    Begin

         total:=0;

         Road[wayin[1],wayin[2]]:=3;                   {入口坐标设置已走标志}

         Howgo(wayin[1],wayin[2]);                     {从入口处开始搜索}

         writeln('Total is ',total);                {统计总数}

    end.

    【题目】一笔画问题

    从某一点出发,经过每条边一次且仅一次.(具体图见高级本P160)

    【参考程序】

    const max=6;{顶点数为6}

    type shuzu=array[1..max,1..max]of 0..max;

    const a:shuzu                         {图的描述与定义 1:连通;0:不通}

           =((0,1,0,1,1,1),

               (1,0,1,0,1,0),

               (0,1,0,1,1,1),

               (1,0,1,0,1,1),

               (1,1,1,1,0,0),

               (1,0,1,1,0,0));

    var

       bianshu:array[1..max]of 0..max; {与每一条边相连的边数}

       path:array[0..1000]of integer;  {记录画法,只记录顶点}

       zongbianshu,ii,first,i,total:integer;

    procedure output(dep:integer); {输出各个顶点的画法顺序}

    var sum,i,j:integer;

    begin

         inc(total);

         writeln('total:',total);

         for i:=0 to dep do write(Path[i]);writeln;

    end;

    function ok(now,i:integer;var next:integer):boolean;{判断第I条连接边是否已行过}

    var j,jj:integer;

    begin

         j:=0; jj:=0;

         while jj<>i do begin  inc(j);if a[now,j]<>0 then inc(jj);end;

         next:=j;

          {判断当前顶点的第I条连接边的另一端是哪个顶点,找出后赋给NEXT传回}

         ok:=true;

         if (a[now,j]<>1)  then  ok:=false;  {A[I,J]=0:原本不通}

    end;                                               {        =2:曾走过}

    procedure init; {初始化}

    var i,j :integer;

    begin

         total:=0;      {方案总数}

         zongbianshu:=0;   {总边数}

         for i:=1 to max do

               for j:=1 to max do

                   if a[i,j]<>0 then begin inc(bianshu[i]);inc(zongbianshu);end;

                   {求与每一边连接的边数bianshu[i]}

         zongbianshu:=zongbianshu div 2;  {图中的总边数}

    end;

     

    procedure find(dep,nowpoint:integer); {dep:画第几条边;nowpoint:现在所处的顶点}

    var i,next,j:integer;

    begin

         for i:=1 to bianshu[nowpoint] do    {与当前顶点有多少条相接,则有多少种走法}

               if ok(nowpoint,i,next) then begin  {与当前顶点相接的第I条边可行吗?}

                                                            {如果可行,其求出另一端点是NEXT}

                  a[nowpoint,next]:=2; a[next,nowpoint]:=2; {置成已走过标志}

                  path[dep]:=next;                           {记录顶点,方便输出}

                  if dep < zongbianshu then find(dep+1,next)  {未搜索完每一条边}

                                          else output(dep);

                  path[dep]:=0;                              {回溯}

                  a[nowpoint,next]:=1; a[next,nowpoint]:=1;

               end;

    begin

       init;   {初始化,求边数等}

       for first:=1 to max do {分别从各个顶点出发,尝试一笔画}

         fillchar(path,sizeof(path),0);

         path[0]:=first;           {记录其起始的顶点}

         writeln('from point ',first,':');readln;

         find(1,first); {从起始点first,一条边一条边地画下去}

    end.

    【题目】城市遍历问题.

    给出六个城市的道路连接图,找出从某一城市出发,遍历每个城市一次且仅一次的最短路径

    及其路程长度.(图见高级本P147}

    【参考程序】

    const

         a:array[1..6,1..6]of 0..10  {城市间连接图.数字表示两城市间的路程}

           =((0,4,8,0,0,0),

             (4,0,3,4,6,0),

             (8,3,0,2,2,0),

             (0,4,2,0,4,9),

             (0,6,2,4,0,4),

             (0,0,0,9,4,0));

    var

       had:array[1..6]of boolean;              {某个城市是否已到过}

       pathmin,path:array[1..6]of integer;     {记录遍历顺序}

       ii,first,i,summin,total:integer;

    procedure output(dep:integer); sum,i,j:integer;

         sum:=0; i:=2 6    {求这条路的路程总长}

         if sum><6 then find(dep+1)

                         else output(dep);

                had[i]:=false;        {回溯}

                path[dep]:=0;

             end;

    end;

    begin

       for first:=1 to 6 do begin        {轮流从每一个城市出发,寻找各自的最短路}

         fillchar(had,sizeof(had),false);

         fillchar(path,sizeof(path),0);

         total:=0;

         SumMin:=maxint;                {最短路程}

         path[1]:=first;had[first]:=true;{处理出发点的城市信息,记录在册并置到过标志}

         find(2);                        {到下一城市}

         writeln('from city ',first,' start,total is:',total,'  the min sum:',summin);

         for i:=1 to 6 do write(PathMin[i]);writeln; {输出某个城市出发的最短方案}

       end;

    end.

    【题目】棋子移动问题

    [参考程序]

    const

         n=3; {n<5}

    type

        ss=string[2*n+1];

        ar=array[1..630]of ss;

    var

       a:ar;

       f,z:array[1..630] of integer;

       i,j,k,m,h,t,k1:integer;

       s,d:ss;

       q:boolean;

    procedure print (x:integer);

    var t:array[1..100] of integer;

        y:integer;

    begin

         y:=0;

         repeat

               y:=y+1;

               t[y]:=x;

               x:=f[x];

         until x=0;

         writeln(a[t[y]]:2*n+4);

         writeln(copy('-------------------------',1,2*n+5));

         for x:=2 to y do writeln(x-1:2,':',a[t[y+1-x]]);

    end;

    begin

         s:='_';d:='_';

         for i:=1 to n do begin

             s:='o'+s+'*';

             d:='*'+d+'o';

         end;

         a[1]:=s;f[1]:=0;z[1]:=n+1;

         q:=false;

         i:=1;j:=2; t:=0;

         repeat

           for h:=1 to 4 do begin

                   k:=z[i];k1:=k;s:=a[i];

                   case h of

                    1:if k>1 then k1:=k-1;

                    2:if k<(2*n+1) then k1:=k+1;

                    3:if (k>2) and (s[k-1]<>s[k-2]) then  k1:=k-2;

                    4:if (k<(2*n)) and(s[k+1]<>s[k+2]) then k1:=k+2;

                   end;

               if k<>k1 then begin

                  s[k]:=s[k1];s[k1]:='_';

                  m:=1;

                  while (a[m]<>s) and (m< j-1) do m:=m+1;

                  if a[m] >>s then begin

                     a[j]:=s;f[j]:=i;z[j]:=k1;

                     if s=d then begin

                        print(j);

                        q:=true;

                     end;

                     j:=j+1;

                  end;

            

       end;

         end; {end for}

         i:=i+1;

      until q or (i=j);

    readln;

    end.

    【题目】求集合元素问题(1,2x+1,3X+1类)

    某集合A中的元素有以下特征:

    (1)数1是A中的元素

    (2)如果X是A中的元素,则2x+1,3x+1也是A中的元素

    (3)除了条件(1),(2)以外的所有元素均不是A中的元素

    [参考程序1]

    uses crt,dos;

    var a:array[1..10000]of longint;

        b:array[1..10000]of boolean;

        times,n,m,long,i:longint;

        hour1,minute1,second1,sec1001:word;

       hour2,minute2,second2,sec1002:word;

    begin

         write('N=');readln(n);

    {    gettime(hour1,minute1,second1,sec1001);

         times:=minute1*60+second1;

         writeln(minute1,':',second1);}

         fillchar(b,sizeof(b),0);

         a[1]:=1;m:=2;long:=1;

         while long<=n do begin

               for i:=1 to long do

                   if (a[i]*2=m-1) or (a[i]*3=m-1) then

                     if not b[m] then begin

                      inc(long);a[long]:=m;b[m]:=true;break;

                   end;

               inc(m);

         end;

    {     gettime(hour2,minute2,second2,sec1002);

         times:=minute2*60+second2-times;

         writeln(minute2,':',second2);

         writeln('Ok! Uses Time: ',times);}

         for i:=1 to n do write(a[i],' ');

    readln;

    end.

    [参考程序2]

    uses crt;

    const n=10000;

    var a:array[1..n] of longint;

        i,j,k,l,y:longint;

    begin

         clrscr;

         fillchar(a,sizeof(a),0);

         i:=1;j:=1;

         a[i]:=1;

         repeat

               y:=2*a[i]+1;

               k:=j;

               while y〈a[k] do begin

                     a[k+1]:=a[k];

                     k:=k-1;

               end;

               if y>a[k] then begin

                  a[k+1]:=y;j:=j+1;

                  end

               else for l:=k+1 to j do a[l]:=a[l+1];

               j:=j+1;

               a[j]:=3*a[i]+1;

               inc(i);

         until k>=n;

         for i:=1 to n do begin

             write(a[i],' ');

             if (i mod 10 =0 ) or (i=n) then writeln

         end;

    end.

    [参考程序3]

    uses crt;

    var a:array[1..10000]of longint;

        n,i,one,another,long,s,x,y:longint;

    begin

         write('n=');readln(n);

         a[1]:=1;long:=1;one:=1;another:=1;

         while longy then begin s:=y;inc(another);end

                       else begin s:=x;inc(one);inc(another);end;

               inc(long);a[long]:=s;

         end;

         for i:=1 to n do write(a[i],' ');

    end.

    [参考程序4]

    var n:integer;

        top,x:longint;

    function init(x:longint):boolean;

    begin

         if x=1 then init:=true

            else if((x-1)mod 2=0)and(init((x-1)div 2))

                         or((x-1)mod 3=0)and(init((x-1)div 3))then

                 init:=true

                 else init:=false;

    end;

    begin

         write('input n:');

         readln(n);

         x:=0;

         top:=0;

         while top< n do begin

               x:=x+1;

               if init(x) then

                  top:=top+1;

                  write(x:8);

               end;

         write('output end.');

         readln

    end.

  • 相关阅读:
    分布式版本控制系统Git的安装与使用
    随笔--第一篇博客
    字符串、文件操作,英文词频统计预处理
    了解大数据的特点、来源与数据呈现方式
    第五次作业-结对项目四则运算 “软件”之升级版
    第四次作业:个人项目-小学四则运算 “软件”之初版
    读《构建之法》1-5章有感
    第二次作业——分布式版本控制系统Git的安装与使用
    第一次作业——感想
    【大数据】字符串、文件操作,英文词频统计预处理
  • 原文地址:https://www.cnblogs.com/ngyifeng/p/3718601.html
Copyright © 2020-2023  润新知