Acwing4244牛的比赛
Acwing4244.牛的比賽
題目部分
N 頭奶牛,編號 1~N,一起參加比賽。
奶牛的戰斗力兩兩不同。
這些奶牛之間已經進行了 M輪兩兩對決。
在對決中,戰斗力高的奶牛一定會戰勝戰斗力低的奶牛。
請問,通過上述 M輪對決的結果,可以確定多少頭奶牛的具體戰斗力排名。
輸入格式
第一行包含兩個整數 N,M。
接下來 M行,每行包含兩個整數 a,b,表示奶牛 a 和奶牛 b 之間進行了對決,并且奶牛 a 戰勝了奶牛 b。
輸出格式
輸出可以確定具體戰斗力排名的奶牛數量。
數據范圍
1≤N≤100,
1≤M≤4500,
數據保證合法。
輸入樣例:
5 5
4 3
4 2
3 2
1 2
2 5
輸出樣例:
2
樣例解釋
2號奶牛輸給了 1,3,4 號奶牛,戰勝了 5 號奶牛,可以確定它的戰斗力排名為 4。
5號奶牛輸給了排在第 4 的 2 號奶牛,所以它的戰斗力排名為 5。
其它奶牛不確定。
解法
首先這道題,雖然大佬們說是板子題,但是對我圖論新手來說,這題還是相當有意思的!學到了很多!
錯誤解法
首先原先的我,是有點懵的,在看到這道題時,我們能夠通過floyd得出這道題?我是怎么也想不出
我只能分析出某頭牛的排名能確定下來,是因為它間接和其余的牛battle過
然后看了下大佬的題解(僅文字部分):
這是link,才做出了錯誤解法
還原下,我做出錯誤解法的思路哈:
我們可以把這些兩頭牛有沒有間接比較過,轉換為每個牛都是對應圖中的節點,然后兩點中可達,則為間接比較過
由此我通過轉換關系把題目圖化了,但是我不是添加單條有向邊,而是添加了雙向邊
賦值為1的,代表著戰勝
賦值為0的,代表著戰敗
想得很美好,由于對floyd算法運行流程不熟悉,導致誤以為只要判斷通過戰敗可達其余點或者戰勝可達其余點即可,可是在floyd過程中,卻是我們可以先通過戰敗邊到另一個點,然后再由這個點選擇戰勝邊接著刷新dist數組,導致算法有問題
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author:天才玩家M
* @date:2023/11/29 16:05
* @description:TODO
*/
public class Main {
static int n,m;
static int N=110;
static int INF=Integer.MAX_VALUE/4;
static int [][]dist=new int[N][N];
public static void floyd(){
for (int k = 1; k <=n; k++) {
for (int i = 1; i <=n; i++) {
for (int j = 1; j <=n ; j++) {
dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
String[] s1 = s.split(" ");
n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
for (int i = 0; i <= n; i++) {
for (int j = 0; j <=n; j++) {
if(i==j){
dist[i][j]=1;
}else{
dist[i][j]=INF;
}
}
}
for (int i = 0; i < m; i++) {
s = br.readLine();s1 = s.split(" ");
int a=Integer.parseInt(s1[0]);
int b=Integer.parseInt(s1[1]);
dist[a][b]=1;//代表可達且勝利
//dist[b][a]=0;不能多出這一條,這只能是a->b單向的
//不對上面的說法是錯的,我們可以設置可達不過要與勝利有所區別
dist[b][a]=0;//代表失敗的可達,
//想法很好,可是你有沒有想過我們失敗的點可以沿著失敗的路線上去到達某個成功的點然后由成功的點再蔓延下去呢?
//這種情況就違背了我們最初的意愿了,只讓他們沿著成功之路或者失敗之路而上,且我們只統計成功之路以及失敗之路
//2:可是這種情況下,如果夾雜成成功與失敗,那我們又不會去統計!!!
//那為什么正確答案為6而我們的為2呢?
//解決了,答案浮出水面了,就是因為不去統計,假如1已經確定是倒數第一,而你唯一贏他的你又不算,那這不就少了嗎?
}
floyd();
int res=0;
for (int i = 1; i <=n; i++) {
int count1=0;
int count=0;
for (int j = 1; j <=n; j++) {
if(dist[i][j]==0){
count1++;
}
else if(dist[i][j]!=INF){
count++;
}
}
if(count==n||count1==n){
res++;
}
}
System.out.println(res);
}
}
正確做法
大佬優雅地解決我一直困擾的戰敗與戰勝,通過僅賦值單向邊,而之后同時判斷if(dist[i][j]<=INF/2||dist[j][i]<=INF/2),來確定這個對手是否交戰過,并且由于僅賦值了戰勝那一條,目前點要么戰勝要么戰敗,而且看得比我的透徹,其實做出錯誤做法時,我就已經被要么戰勝要么戰敗給迷惑了,
可是實際情況下是只要戰過,無論成敗即知排名(挺好想的,只要交手過,贏你的在前,輸你的在后,你一定可以找到個位置).
至于INF/2是由于邊比較多設定的,其他的也行
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author:天才玩家M
* @date:2023/11/29 20:38
* @description:TODO
*/
public class Main1 {
static int n,m;
static int N=110;
static int INF=Integer.MAX_VALUE/2;
static int [][]dist=new int[N][N];
public static void floyd(){
for (int k = 1; k <=n; k++) {
for (int i = 1; i <=n; i++) {
for (int j = 1; j <=n ; j++) {
dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
String[] s1 = s.split(" ");
n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
for (int i = 0; i <= n; i++) {
for (int j = 0; j <=n; j++) {
if(i==j){
dist[i][j]=1;
}else{
dist[i][j]=INF;
}
}
}
for (int i = 0; i < m; i++) {
s = br.readLine();s1 = s.split(" ");
int a=Integer.parseInt(s1[0]);
int b=Integer.parseInt(s1[1]);
dist[a][b]=1;
}
floyd();
int res=0;
for (int i = 1; i <=n; i++) {
int count=0;
for (int j = 1; j <=n; j++) {
if(dist[i][j]<=INF/2||dist[j][i]<=INF/2){
count++;
}
}
if(count==n){
res++;
}
}
System.out.println(res);
}
}
總結
以上是生活随笔為你收集整理的Acwing4244牛的比赛的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vite4+Typescript+Vue
- 下一篇: xv6:labs2 syscall