uva 11419 SAM I AM (最小覆盖 König定理)

uva 11419 SAM I AM

题目大意:给出一个R×C的网格,网格上棉纺了一些目标。可以在网格外发射子弹,子弹会沿着垂直或水平方向飞行,并且打掉飞行路径上的所有目标。你的任务是计算出最少需要多少子弹,各从哪个位置发射,才能把所有目标全部打掉。
解题思路:König定理:最小覆盖数等于最大匹配数。把目标所在的坐标,转化为XY结点,行看成X结点,列看成Y结点。那现在问题就变成了,如何选最少的结点,覆盖所有的边。
求最小覆盖的步骤大致如下:1)在右边找到一个未被匹配过的点,标记。2)走一条没被匹配过的边,到左边的点,标记。3)走一条匹配过的边到右边,标记。4)重复2,3步骤直到不能再走。5)回到步骤一,直到找不到未被匹配且未被标记的右边的点。6)标记结束后,右边没有标记的点,和左边标记过的点,就可以覆盖所有的边。

想理解的更透彻,可以看这里

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;

const int N = 1005;
typedef long long ll;
int n, m, k;
vector<int> X, Y;

void init() {
    X.clear();
    Y.clear();
}

struct BPM{  
    int n, m;  
    vector<int > G[N];  
    int left[N];  
    int right[N];  
    bool T[N];  
    bool S[N];  

    void init(int n,int m){  
        this->n = n;  
        this->m = m;  
        for(int i = 0; i < N; i++) G[i].clear();  
    }  

    void addEdge(int u, int v){  
        G[u].push_back(v);  //建边
    }  

    bool match(int u) {  
        S[u] = true; //标记右边的点u
        for(int i = 0; i < G[u].size(); i++){ //遍历由u点出发,连接的左边的点 
            int v = G[u][i]; 
            if(!T[v]){  //左边的没标记过的点, 走没匹配过的边
                T[v] = true;  
                if(left[v] == -1 || match(left[v])){ //走匹配过的边到右边的点
                    left[v] = u;  
                    right[u] = v;  
                    return true;  
                }  
            }  
        }  
        return false;  
    }  

    int solve(){  
        memset(left, -1, sizeof(left));  
        memset(right, -1, sizeof(right));  
        int ans = 0;  
        for(int u = 0; u < n; u++){  
            memset(S, 0, sizeof(S));  
            memset(T, 0, sizeof(T));  
            if(match(u)) ans++;  //先用匈牙利算法求出最大匹配
        }  
        return ans;  
    }  

    int mincover(vector<int>& X, vector<int>& Y){  
        int ans = solve();  
        memset(S, 0, sizeof(S));  
        memset(T, 0, sizeof(T));  
        for(int u = 0; u < n; u++) //在右边的点集找到一个未被标记的点  
            if(right[u] == -1) match(u); //从这个未标记的点开始走增广路 
        for(int u = 0; u < n; u++)  
            if(!S[u]) X.push_back(u); //标记结束之后,记录右边没标记的点 
        for(int v = 0; v < n; v++)  
            if(T[v]) Y.push_back(v);  //记录左边标记过的点
        return ans;  
    }  
}bpm;  

void input() {
    int x, y;
    for (int i = 0; i < k; i++) {
        scanf("%d %d", &x, &y); 
        x--, y--;
        bpm.addEdge(x, y);
    }
}

int main() {
    while (scanf("%d %d %d", &n, &m, &k) == 3)  {
        if (!n && !m && !k) break;
        bpm.init(n, m);         
        init();
        input();
        printf("%d", bpm.mincover(X, Y));
        for (int i = 0; i < X.size(); i++) printf(" r%d", X[i] + 1);
        for (int i = 0; i < Y.size(); i++) printf(" c%d", Y[i] + 1);
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Python实现NIG分布的代码示例: ```python import numpy as np from scipy.special import gamma, kv class NIG: def __init__(self, alpha, beta, mu, delta): self.alpha = alpha self.beta = beta self.mu = mu self.delta = delta def pdf(self, x): z = np.sqrt(self.alpha**2 - self.beta**2) sqrt_term = self.alpha * np.sqrt(self.beta / (np.pi * x**3)) * np.exp((self.beta**2 - 2 * self.alpha * x) / (2 * self.delta * x)) cosine_term = np.exp(z * (self.mu - x)) * kv(1, z * np.sqrt(self.delta * x)) return sqrt_term * cosine_term def cdf(self, x): z = np.sqrt(self.alpha**2 - self.beta**2) x_ = np.sqrt(self.delta) * (x - self.mu) y = np.sqrt(self.delta) * self.beta / z t = 1 / (1 + x_ / z) return 0.5 * (1 + np.sign(x_) * (1 - np.exp(-y * t)) / (np.exp(x_ / z) * kv(1, y) * t**2)) def mean(self): if self.beta > 0: return self.mu + self.delta * self.beta / self.alpha else: return np.inf def variance(self): if self.beta > 2 * self.alpha**2: return np.inf else: return self.delta * (self.alpha**2 - self.beta**2) / (self.alpha**2 * (self.beta - 2 * self.alpha**2)) def skewness(self): if self.beta > 3 * self.alpha**2: return np.nan else: return 3 * self.beta * np.sqrt(self.delta) / (self.alpha * np.sqrt(self.alpha**2 - self.beta**2)) def kurtosis(self): if self.beta > 4 * self.alpha**2: return np.nan else: return 3 + 4 * (self.delta * self.beta**2 / (self.alpha**2 * (self.beta - 3 * self.alpha**2)) - 1) def entropy(self): return np.log(np.sqrt(self.alpha**2 / (self.delta * self.beta)) * gamma(1/2 * (1 + (self.beta**2 / self.alpha**2))) / np.sqrt(np.pi)) def rvs(self, size=1): gamma_samples = np.random.gamma(shape=self.alpha**2 / self.delta, scale=self.delta, size=size) normal_samples = np.random.normal(loc=self.mu, scale=np.sqrt(self.delta / self.beta), size=size) return normal_samples + self.beta / self.alpha * np.sqrt(gamma_samples) ``` 上面的代码中,我们定义了一个名为`NIG`的类,它包含了NIG分布的各种方法,例如概率密度函数`pdf`、累积分布函数`cdf`、均值`mean`、方差`variance`、偏度`skewness`、峰度`kurtosis`、熵`entropy`和随机变量生成函数`rvs`。在初始化时,我们需要提供NIG分布的参数,即$\alpha$,$\beta$,$\mu$和$\delta$。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值