Petri网可达分析算法

Petri网导论这本教材第三章的算法

C++实现

输入 为 库所和变迁个数 以及关联矩阵

4 4
1 -1 0 0
-1 1 1 0
1 0 -1 -1
0 -1 -1 1
1 0 0 0
3 4
-1 1 0
1 -1 0
0 1 -1
0 -1 1
0 1 0

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>

using namespace std;

#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007

#define mp make_pair
#define fi first
#define se second

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m=(l+r)>>1

using namespace std;

const int nmax = 1000 + 10;
const int tmax = 100 + 10;
const int pmax = 100 + 10;

int np, nt;//输入库所和变迁个数
int A[tmax][pmax];//输入关联矩阵
int A1[tmax][pmax], A2[tmax][pmax];//输出矩阵A+ 和输入矩阵A-
int M0[pmax];//输入初始标识
int M[pmax], M1[pmax];//当前标识

struct Node {//CT节点
    int m[pmax];//标识向量
    struct Node* parent;//指向父节点的指针
    int t;//变迁编号 1,2……,nt(对应下标+1)
    int flag;//标记 0为新,1为旧,-1为端点

    Node() {
        memset(m, 0 ,sizeof(m));
        parent = NULL;
        t = 0;
        flag = 0;
    };
} Tr[nmax];

bool repeat(int i) {//true为M是重复节点
    for(int j = 0; j < np; ++j) {
        if(M[j] != Tr[i].m[j]) return false;
    }
    return true;//M(j) == m[j] j=1,2,...,np
}

bool check(int i) {// true为ti可发生
    for(int j = 0; j < np; ++j) {
        if(M[j] < A2[i][j]) return false;
    }
    return true;//M[ti> 充要条件:M(j)>=aij j=1,2,...,np
}

int main() {
    freopen("input.txt",  "r", stdin);
    freopen("output.txt", "w", stdout);
    int cases = 0;

    /* 输入库所个数np和变迁个数nt,0 0结束输入 */
    while(~scanf("%d %d", &np, &nt) && (np != 0 || nt != 0)) {

        printf("Case %d:\n", ++cases);
        int CR = 0;//1为可覆盖树,0为可达树
        int k = 0;//记录CT中节点的个数

        /* 清理上一组数据 */
        memset(Tr, 0, sizeof(Tr));
        memset(A,  0, sizeof(A));
        memset(A1, 0, sizeof(A1));
        memset(A2, 0, sizeof(A2));
        memset(M0, 0, sizeof(M0));
        memset(M,  0, sizeof(M));
        memset(M1, 0, sizeof(M1));

        /* 输入关联矩阵A和初始标识M0 */
        for(int i = 0; i < nt; ++i) {
            for(int j = 0; j < np; ++j) {
                scanf("%d", &A[i][j]);
                if(A[i][j] == 1)  A1[i][j] =  A[i][j];
                if(A[i][j] == -1) A2[i][j] = -A[i][j];
            }
        }//关联矩阵

        /* step0 以初始标识为CT的根节点,并标为新=0 */
        Node *head;//空的头节点
        head = (Node*)malloc(sizeof(struct Node));
        head->parent = NULL;
        Tr[k].parent = head;//根节点(初始标识)M0=Tr[0] 指向空的头节点head
        for(int i = 0; i < np; ++i) {
            scanf("%d", &M0[i]);
            Tr[k].m[i] = M0[i];//Tr[0]为CT根节点
        }//初始标识
        k++;//目前只有一个根节点k=1

        /* step1 是否存在新=0的节点,任选一个新的节点为当前节点=M */
        while(1) {
            int nnew = -1;//当前节点(标识)的下标
            for(int i = 0; i < k; ++i) {
                if(Tr[i].flag == 0) {
                    nnew = i;//有新节点,下标为i
                    break;
                }
            }if(nnew == -1) {//判断没有新的节点,结束while
                break;
            }//step1 结束,否则继续

            /* 将任意一个新节点设置为当前节点=M */
            for(int i = 0; i < np; ++i) {
                M[i] = Tr[nnew].m[i];
            }

            /* step2 根节点=head 到 当前节点=M 的路径上 如果有重复标为旧flag=1 */
            int rep = 0;
            Node *q = Tr[nnew].parent;//q指向当前节点M的父节点
            while(q->parent != NULL) {
                int f = 0;
                for(int j = 0; j < np; ++j) {
                    if(M[j] != q->m[j]) f = 1;
                }if(f == 0) {//M是重复节点
                    Tr[nnew].flag = 1;//标为旧=1
                    rep = 1;
                    break;
                }
                q = q->parent;
            }if(rep == 1) {
                continue;//返回while,step1
            }//step2 结束,不标为旧则继续

            /* step3 当前节点=M 如果所有的变迁都是死的标为端点=-1 */
            int dead = -1;
            for(int i = 0; i < nt; ++i) {
                if(check(i)) {//存在可发生的变迁ti
                    dead = i;
                    break;
                }
            }if(dead == -1) {
                Tr[nnew].flag = -1;//所有的变迁都不可发生,标为端点=-1
                continue;//返回while,step1
            }//step3 结束,不标为端点则继续

            /* step4 对每个可发生的t */
            for(int i = 0; i < nt; ++i) {//遍历每一个变迁t
                if(check(i)){//ti可发生
                    for(int j = 0; j < np; ++j) {
                        /* 计算M1 */
                        if(M[j] == 'w') M1[j] = M[j];
                        else M1[j] = M[j] + A[i][j];
                        Tr[k].m[j] = M1[j];
                    }

                    /* 插入w分量 */
                    Node *p = &Tr[nnew];//p指向当前节点M
                    while(p->parent != NULL) {
                        int f = 0;
                        for(int j = 0; j < np; ++j) {
                            if(p->m[j] > M1[j]) {
                                f = -1;//不满足条件
                                break;
                            }
                        }if(f == 0) {
                            for(int j = 0; j < np; ++j) {
                                if(p->m[j] < M1[j]) {
                                    Tr[k].m[j] = 'w';
                                    CR = 1;//存在w分量
                                }
                            }
                        }
                        p = p->parent;
                    }//判断是否有无穷w

                    /* 插入新节点 */
                    Tr[k].parent = &Tr[nnew];//有向弧
                    Tr[k].t = i + 1;//有向弧旁标
                    Tr[nnew].flag = 2;//抹去标注
                    k++;//节点个数增加
                }
            }//step4 结束,创建了新节点,继续找标为新=1的节点
        }//无标为新的节点,while结束
        /* step1 结束,算法结束 */

        /* 输出得到可覆盖树CT或者可达树RT */
        if(CR == 0) printf("The tree is reachability tree ");
        else        printf("The tree is coverability tree ");
        printf("of %d nodes.\n", k);
        for(int i = 0; i < k; ++i) {
            for(int j = 0; j < np; ++j) {
                if(j == 0) printf("M%d = [", i);
                if(Tr[i].m[j] != 'w') printf("%d", Tr[i].m[j]);
                else printf("%c", Tr[i].m[j]);
                if(j != np - 1) printf(",");
                else printf("]");
            }

            if(Tr[i].t != 0) printf(" t%d", Tr[i].t);

            if(Tr[i].parent != head) {
                for(int j = 0; j < np; ++j) {
                    if(j == 0) printf(" parent = [");
                    if(Tr[i].parent->m[j] != 'w') printf("%d", Tr[i].parent->m[j]);
                    else printf("%c", Tr[i].parent->m[j]);
                    if(j != np - 1) printf(",");
                    else printf("]");
                }
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

16年12月完成 现在只是存一下(主要比较好找)

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值