1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ABC - 080- A&B&C

Last updated at Posted at 2019-03-25

#AtCoder ABC 080 B&C
AtCoder - 080

2015/05/23
 問題名追記・C問題のDFSでの解法追記
2015/05/23
 C問題のDFS解法について別解追記(フラグの管理をint[]からbitに置き換えたもの)

#A - Parking

  • $T$ 時間駐車した場合 $T*A$ 円
  • 駐車した時間$T$にかかわらず $B$ 円
  • どちらが安いか?
	private void solveA() {
		Scanner scanner = null;
		int numN = 0;
		int numA = 0;
		int numB = 0;

		try {
			scanner = new Scanner(System.in);
			numN = scanner.nextInt();
			numA = scanner.nextInt();
			numB = scanner.nextInt();

			System.out.println(Math.min(numA * numN, numB));

		} finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}

#B - Harshad Number

  • $X$の各桁の和を求める
  • $mod 各桁の和 = 0 $ かどうか判定

各桁の和をついつい再帰で求めている。whileの方が速いんじゃないか?


	private void solveB() {
		Scanner scanner = null;
		int numN = 0;

		try {
			scanner = new Scanner(System.in);
			numN = scanner.nextInt();

			int res = addAllDigit(numN);

			if (numN % res == 0) {
				System.out.println("Yes");
			} else {
				System.out.println("No");

			}

		} finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}

	private int addAllDigit(int num) {
		if (num < 10) {
			return num;
		}
		return addAllDigit(num / 10) + num % 10;
	}

#C - Shopping Street

###bitマスク利用版

  • $F_1 ・・・ F_n$ まで店がある
  • お店の営業時間は午前午後で10通り
  • 自分のお店の営業時間を $2^{10}$ 通りの中から選択して営業利益が最大になるものを探す

必要なものとして、

  • 自分の店の $2^{10}$ 通りの営業時間をどう表現するのか?

がある。

forで1023回回して都度bit配列を生成すれば、マスク用の配列を生成できる。

  • 0000000000=どの時間帯でも営業していないはNGなので$1024-0$通り

####マスク用のコード

		//0000000000から、1111111111までの配列を作成。2の剰余を入れていけば2進数に変換できる。
		for (int i = 1; i < 1024; i++) {
			int[] myShop = new int[10];
			int wkBit = i;
			for (int j = 0; j < 10; j++) {
				myShop[j] = wkBit % 2;
				wkBit /= 2;
			}
		}

####C問題解答の本体コード

  • 自分のお店の取りうる営業時間分( $ 2^{10}$通り )ループ
    • マスク用配列生成ループ
    • 一つのお店の営業時間をマスク
      • お店の営業時間とマッチする時間帯をカウント
    • 利益が最大となるものを取得
	private void solveC() {
		Scanner scanner = null;
		int numN = 0;

		try {
			scanner = new Scanner(System.in);
			numN = scanner.nextInt();

			int[][] shop = new int[numN][10];
			int[][] rieki = new int[numN][11];

			for (int j = 0; j < numN; j++) {
				for (int k = 0; k < 10; k++) {
					shop[j][k] = scanner.nextInt();
				}
			}

			for (int j = 0; j < numN; j++) {
				for (int k = 0; k < 11; k++) {
					rieki[j][k] = scanner.nextInt();
				}
			}
			int res = Integer.MIN_VALUE;
			//0000000000=0、1111111111=1023
			for (int i = 1; i < 1024; i++) {
				int wkRes = 0;
				int[] myShop = new int[10];
				int wkBit = i;
				//0000000000から、1111111111までの配列を作成。2の剰余を入れていけば2進数に変換できる。
				for (int j = 0; j < 10; j++) {
					myShop[j] = wkBit % 2;
					wkBit /= 2;
				}
				for (int j = 0; j < shop.length; j++) {
					int cnt = 0;
					for (int k = 0; k < myShop.length; k++) {
						if (myShop[k] == shop[j][k] && myShop[k] == 1) {
							cnt++;
						}
					}
					wkRes += rieki[j][cnt];
				}
				res = Math.max(res, wkRes);
			}

			System.out.println(res);

		} finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}

###DFS版


	/**
	 * DFS
	 */
	private void solveC3() {

		try (Scanner scanner = new Scanner(System.in)) {

			int numN = scanner.nextInt();

			int[][] shop = new int[numN][10];
			int[][] rieki = new int[numN][11];

			for (int j = 0; j < numN; j++) {
				for (int k = 0; k < 10; k++) {
					shop[j][k] = scanner.nextInt();
				}
			}

			for (int j = 0; j < numN; j++) {
				for (int k = 0; k < 11; k++) {
					rieki[j][k] = scanner.nextInt();
				}
			}
			/*
			 * DFSで調べる
			 * new int[10] => joisinoお姉ちゃんがopenする時間帯のmemo
			 */
			int res = recursiveC(shop, rieki, new int[10], 0, numN);

			System.out.println(res);

		}
	}

	private int recursiveC(int[][] shop, int[][] rieki, int[] joisinoShop, int currentI, int shopNum) {

		/*
		 * お店のopen時間は10種類
		 * currentI>=10になったので、joisinoShopを埋め終わりOpenする時間帯を決定した。
		 * 利益計算
		 */
		if (currentI >= 10) {
			int res = 0;
			for (int j = 0; j < shop.length; j++) {
				int cnt = 0;
				boolean isOpen = false;
				for (int k = 0; k < 10; k++) {
					if (shop[j][k] == 1 && joisinoShop[k] == 1) {
						cnt++;
					}
					//どこかの時間帯でopenしているのであればopenフラグON
					if (joisinoShop[k] == 1 && !isOpen) {
						isOpen = true;
					}
				}
				/*
				 * 何処もopenしないのはNG
				 * 利益を最低にする
				 */
				if (!isOpen) {
					return Integer.MIN_VALUE;
				}
				res += rieki[j][cnt];
			}
			return res;
		}
		//currentIの時間帯にopenしなかった場合のコスト
		int val1 = recursiveC(shop, rieki, joisinoShop, currentI + 1, shopNum);
		//currentIの時間帯のopenした場合のコスト
		joisinoShop[currentI] = 1;
		int val2 = recursiveC(shop, rieki, joisinoShop, currentI + 1, shopNum);
		//次の探索用にopenフラグを落とす
		joisinoShop[currentI] = 0;
		return Integer.max(val1, val2);

	}

###DFS+フラグ管理をbitで行う

参考:
ビット演算 (bit 演算) の使い方を総特集! 〜 マスクビットから bit DP まで 〜

  • 基本的な動きはDFS版と同じ。どこの時間帯でopenするかのチェック方法を変更
  • new int[10] なんていらなかったんや・・・
	private void solveC3() {

		try (Scanner scanner = new Scanner(System.in)) {

			int numN = scanner.nextInt();

			int[][] shop = new int[numN][10];
			int[][] rieki = new int[numN][11];

			for (int j = 0; j < numN; j++) {
				for (int k = 0; k < 10; k++) {
					shop[j][k] = scanner.nextInt();
				}
			}

			for (int j = 0; j < numN; j++) {
				for (int k = 0; k < 11; k++) {
					rieki[j][k] = scanner.nextInt();
				}
			}
			/*
			 * DFSで調べる
			 * joisinoShop => joisinoお姉ちゃんがopenする時間帯をmemoするmemo用
			 */
			int res = recursiveCNotUseArray(shop, rieki, 0, 0, numN);

			System.out.println(res);

		}
	}

	private int recursiveCNotUseArray(int[][] shop, int[][] rieki, int joisinoShop, int currentI, int shopNum) {

		/*
		 * お店のopen時間は10種類
		 * currentI>=10になったので、joisinoShopを埋め終わりOpenする時間帯を決定した。
		 * 利益計算
		 */
		if (currentI >= 10) {
			/*
			 * 何処もopenしないのはNG
			 * 利益を最低にする
			 */
			if (joisinoShop == 0) {
				return Integer.MIN_VALUE;
			}
			//どこかの時間帯でopenしているのであれば計算
			int res = 0;
			for (int j = 0; j < shop.length; j++) {
				int cnt = 0;
				for (int k = 0; k < 10; k++) {
					if (shop[j][k] == 1 && (joisinoShop & (1 << k)) > 0) {
						cnt++;
					}
				}
				res += rieki[j][cnt];
			}
			return res;
		}
		//currentIの時間帯にopenしなかった場合のコスト
		int val1 = recursiveCNotUseArray(shop, rieki, joisinoShop, currentI + 1, shopNum);
		//currentIの時間帯にopenした場合のコスト
		joisinoShop = joisinoShop | (1 << currentI);
		int val2 = recursiveCNotUseArray(shop, rieki, joisinoShop, currentI + 1, shopNum);
		//次の探索用にopenフラグを落とす
		joisinoShop = joisinoShop ^ (1 << currentI);
		return Integer.max(val1, val2);

	}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?